gpt4 book ai didi

javascript - 如何在 Apollo 客户端的初始化中使用来自 React 的全局数据?

转载 作者:行者123 更新时间:2023-12-04 13:25:07 25 4
gpt4 key购买 nike

说到状态集中,我知道如何使用 context api 和 Redux。但是要恢复这种状态,我们总是必须在一个 react ​​组件中。
访问不在 react 组件内的公共(public)函数内的全局状态/变量的最佳策略是什么?
在环境变量中不是一个选项,因为此值在应用程序运行后更改。出于安全原因,我不想放入 cookie 或本地存储。
索引.ts

import React from 'react';
import ReactDOM from 'react-dom';
import { ApolloProvider } from 'react-apollo';
import apolloClient from './services/apollo';

import { PersonalTokenProvider } from './providers/personal-token';
import './index.css';
import App from './App';

ReactDOM.render(
<React.StrictMode>
<PersonalTokenProvider>
<ApolloProvider client={apolloClient}>
<App />
</ApolloProvider>
</PersonalTokenProvider>
</React.StrictMode>,
document.getElementById('root'),
);
PresonalToken 上下文提供者
import React, { useState } from 'react';

interface ProviderProps {
children: JSX.Element[] | JSX.Element;
}

export const PersonalTokenContext = React.createContext({});

export const PersonalTokenProvider: React.FC<ProviderProps> = (
props: ProviderProps,
) => {
const [token, setToken] = useState<string | null>(null);

const { children } = props;

return (
<PersonalTokenContext.Provider value={{ token, setToken }}>
{children}
</PersonalTokenContext.Provider>
);
};
Apollo 客户端配置
import { useContext } from 'react';
import { ApolloClient } from 'apollo-client';
import { HttpLink } from 'apollo-link-http';
import { InMemoryCache } from 'apollo-cache-inmemory';
import { PersonalTokenContext } from '../providers/personal-token';

//cant do this
const {token} = useContext(PersonalTokenContext)

const httpLink = new HttpLink({
uri: 'https://api.github.com/graphql',
headers: {
authorization: `Bearer ${token}`,
},
});

const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache(),
});

export default client;

最佳答案

纯 React Apollo 客户端初始化
有多种方法可以模拟单例以在 React 中管理 Apollo 客户端。这是使用 useRef 的一种方法在进行 GraphQL 查询和 useMemo 时始终拥有最新的 token 只创建一次客户端。

import {
ApolloClient,
createHttpLink,
InMemoryCache,
ApolloProvider
} from '@apollo/client';
import { setContext } from '@apollo/client/link/context';

// The name here doesn't really matters.
export default function CustomApolloProvider(props) {
const { token } = useContext(PersonalTokenContext);
const tokenRef = useRef();

// Whenever the token changes, the component re-renders, thus updating the ref.
tokenRef.current = token;

// Ensure that the client is only created once.
const client = useMemo(() => {
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
authorization: tokenRef.current ? `Bearer ${tokenRef.current}` : '',
}
}));

const httpLink = createHttpLink({
uri: 'https://api.github.com/graphql',
});

return new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
}, [])

return <ApolloProvider client={client} {...props} />;
}
然后在应用程序中:
    <PersonalTokenProvider>
<CustomApolloProvider>
<App />
</CustomApolloProvider>
</PersonalTokenProvider>
优点:
  • 完全在 React 内部,这意味着它可以使用从不同位置更改的其他钩子(Hook)和数据,例如翻译库中的语言环境代码等。
  • 每个已安装的应用程序一个客户端,这意味着,如果需要卸载应用程序,此解决方案将确保正确清理。
  • 易于添加单元/集成测试

  • 缺点:
  • 安装起来稍微复杂一些。
  • 如果设置不正确,最终可能会创建多个 Apollo 客户端,从而丢失之前的缓存等。

  • 使用本地存储
    Apollo documentation建议使用本地存储来管理身份验证 token 。
    import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
    import { setContext } from '@apollo/client/link/context';

    const httpLink = createHttpLink({
    uri: '/graphql',
    });

    const authLink = setContext((_, { headers }) => {
    // get the authentication token from local storage if it exists
    const token = localStorage.getItem('token');
    // return the headers to the context so httpLink can read them
    return {
    headers: {
    ...headers,
    authorization: token ? `Bearer ${token}` : "",
    }
    }
    });

    const client = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache()
    });

    优点:
  • 很容易添加到您现有的实现中
  • 在应用程序的整个生命周期内只创建一个客户端
  • 本地存储是存储全局数据的好地方横跨标签、刷新等

  • 缺点:
  • 存在于 React 之外,因此当 token 更改等时应用程序不会重新渲染。
  • 单元测试可能更难/复杂。

  • 使用模块范围变量
    在模块的根目录使用一个简单的变量就足够了,您甚至不再需要 token 上下文。
    import {
    ApolloClient,
    createHttpLink,
    InMemoryCache,
    makeVar
    } from '@apollo/client';
    import { setContext } from '@apollo/client/link/context';

    // module scoped var for the token:
    let token;

    // custom module setter:
    export const setToken = (newToken) => token = newToken;

    const httpLink = createHttpLink({
    uri: '/graphql',
    });

    // Apollo link middleware gets called for every query.
    const authLink = setContext((_, { headers }) => ({
    headers: {
    ...headers,
    authorization: token ? `Bearer ${token}` : "",
    }
    }
    ));

    export const client = new ApolloClient({
    link: authLink.concat(httpLink),
    cache: new InMemoryCache()
    });
    优点:
  • 很容易添加到您现有的实现中
  • 在应用程序的整个生命周期内只创建一个客户端

  • 缺点:
  • 存在于 React 之外,因此当 token 更改等时应用程序不会重新渲染。
  • 单元测试可能更难/更复杂
  • 当用户刷新页面或关闭应用程序时丢失。

  • 用于管理 token 的响应式(Reactive)变量
    juanireyes建议 Apollo Reactive variables ,但它们适用于特定的用例,完全没有必要像我们在这里想要的那样在全局范围内管理 token 。它类似于上面的模块范围变量建议,但有额外的步骤。

    关于javascript - 如何在 Apollo 客户端的初始化中使用来自 React 的全局数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68886359/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com