简体   繁体   English

如何在 React 中创建使用外部上下文的类服务提供者?

[英]How to create a class service provider that consumes an external context in React?

I'm trying to create a service class that provides the whole application with common access to an e xternal Rest api.我正在尝试创建一个服务类,为整个应用程序提供对外部 Rest api 的公共访问。

The first issue I face is that this external api needs to be consumed as a Context, so my first approach was to create a custom context to consume and configure all the rest calls.我面临的第一个问题是这个外部 api 需要作为 Context 使用,所以我的第一种方法是创建一个自定义上下文来使用和配置所有其余的调用。 See code:见代码:

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>
    );
};

This works fine.这工作正常。 I can configure and make the calls all around the application.我可以在应用程序周围配置和进行调用。 The problem is: Whenever I make any of these calls, all of them are re-rendered as my context seems to have changed .问题是:每当我进行这些调用中的任何一个时,所有这些调用都会重新呈现,因为我的上下文似乎已经改变了

So I have 2 doubts:所以我有两个疑问:

  1. Is this code correct to provide a general place to provide with a Context that provides with an external Rest api context?这段代码是否正确提供了一个通用位置来提供一个提供外部 Rest api 上下文的上下文? I am missing something that makes the context re-render?我错过了使上下文重新呈现的东西?

By the other hand, I was trying to create a service class like posted here: https://newbedev.com/having-services-in-react-application .另一方面,我试图创建一个像这里发布的服务类: https : //newbedev.com/have-services-in-react-application But then, inside a service class, a Context cannot be used... So...但是,在服务类中,不能使用 Context ......所以......

  1. Is there any way to create a common service Class that is able to consume an external Context api?有没有办法创建一个能够使用外部上下文 api 的公共服务类?

Thanks in advance!提前致谢!

As a start, you need to realize why your components re-render:首先,您需要了解为什么您的组件要重新渲染:

ApiProvider re-renders because, either it's parent component re-renders or because children changed. ApiProvider重新渲染,因为它的父组件重新渲染或因为children组件发生了变化。 children is the most obvious candidate here. children是这里最明显的候选人。

The problem then is that every time ApiProvider renders, you provide a completely new context value:那么问题在于,每次ApiProvider呈现时,您都会提供一个全新的上下文值:

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

Which forces every consumer of that context value to re-render as well.这迫使该上下文值的每个消费者也重新渲染。 The simplest solution would be to wrap everything with useCallback and the context value itself with useMemo .最简单的解决办法是用包裹一切useCallback与上下文值本身useMemo

Something like:就像是:

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}/>
  );
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM