【问题标题】:How to create a class service provider that consumes an external context in React?如何在 React 中创建一个使用外部上下文的类服务提供者?
【发布时间】:2021-11-08 08:40:48
【问题描述】:

我正在尝试创建一个服务类,为整个应用程序提供对外部 Rest api 的公共访问。

我面临的第一个问题是这个外部 api 需要作为一个上下文来使用,所以我的第一个方法是创建一个自定义上下文来使用和配置所有其余的调用。见代码:

export const ApiContext = createContext();

const ApiProvider = ({ children }) => {
    const api = externalApiContext();

    const get = (url, params) =>
        api.get(urlWithParams(`${baseUrl}${url}${admkey}`, params));

    const post = (url, body, params = {}, headers = {}) =>
        api.post(urlWithParams(`${baseUrl}${url}${admkey}`, params), {
            headers: { ...headers, 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
        });

    const put = (url, body, params = {}, headers = {}) =>
        api.put(urlWithParams(`${baseUrl}${url}${admkey}`, params), {
            headers: { ...headers, 'Content-Type': 'application/json' },
            body: JSON.stringify(body),
        });

    const remove = (url, params = {}, headers = {}) =>
        api.remove(urlWithParams(`${baseUrl}${url}${admkey}`, params), {
            headers: { ...headers, 'Content-Type': 'application/json' },
        });

    const fetch = (url) => api.get(`${url}`);

    return (
        <ApiContext.Provider value={{ get, post, put, remove, fetch }}>
            {children}
        </ApiContext.Provider>
    );
};

这很好用。我可以围绕应用程序进行配置和调用。 问题是:每当我进行任何这些调用时,它们都会重新渲染,因为我的上下文似乎发生了变化

所以我有两个疑问:

  1. 此代码是否正确,可以提供一个通用位置来提供一个提供外部 Rest api 上下文的上下文?我遗漏了使上下文重新呈现的内容?

另一方面,我正在尝试创建一个服务类,就像这里发布的那样:https://newbedev.com/having-services-in-react-application。但是,在服务类中,不能使用上下文......所以......

  1. 有没有办法创建一个能够使用外部 Context api 的通用服务类?

提前致谢!

【问题讨论】:

    标签: reactjs react-context


    【解决方案1】:

    首先,您需要了解组件重新渲染的原因:

    ApiProvider 重新渲染是因为它的父组件重新渲染或因为 children 更改。 children 是这里最明显的候选人。

    那么问题在于,每次ApiProvider 呈现时,您都会提供一个全新的上下文值:

    <ApiContext.Provider value={{ get, post, put, remove, fetch }}>
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                                      \ new object everytime!
    

    这会迫使该上下文值的每个消费者也重新渲染。最简单的解决方案是用useCallback 包装所有内容,用useMemo 包装上下文值本身。

    类似:

    export const ApiContext = createContext();
    
    const ApiProvider = ({ children }) => {
      const api = externalApiContext();
      
      const get = useCallback(
        (url, params) => api.get(urlWithParams(`${baseUrl}${url}${admkey}`, params)),
        [api]
      );
      
      // ...repeat for a others...
      
      return (
        <ApiContext.Provider value={useMemo(
          () => ({ get, post, put, remove, fetch }),
          [get, post, put, remove, fetch]
        )} children={children}/>
      );
    };
    

    【讨论】:

    • 我尝试了您的解决方案,但我必须重新检查,因为它一直在重新渲染...我会改进我的解决方案,看看它是否符合您的建议。
    • 别担心!也许你可以解释一下externalApiContext(); 是什么。如果这是一个钩子实现(或其他随时间变化的东西),那么它也可能负责重新渲染。而且因为所有回调和最终的上下文值都依赖于 api 值,所以可能很难/不可能阻止从 ApiProvider 内部重新渲染。
    • 好的,成功了!非常感谢您的帮助^^
    猜你喜欢
    • 2018-07-09
    • 1970-01-01
    • 2019-11-24
    • 2021-07-30
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-06
    相关资源
    最近更新 更多