Joey Coder
Joey Coder

Reputation: 3489

Switching context causes re-render of the whole component

I am currently facing the challenge, that I have two different components in my Layout.js component. These two components must "share" props with each other. To solve that I added a ContextProvider IntegrationProvider.

However, now I am having the issue, whenever currentElement.type is changing (and therefore the IntegrationProvider changes), the whole Layout component re-renders. My current best idea is to create one ContextProvider for all integrations together. However, this would lead to many unnecessary props in other integrations. Do you have a better idea?

Space.js

<IntegrationProvider>
  <Layout
    [props...]
  />
</IntegrationProvider>

IntegrationProvider.js

const integrationProvider = {
  [INTEGRATION_TYPE.DAILY]: IntegrationProviderDaily,
};

const IntegrationProvider = ({ children }) => {
  const currentElement = useSelector(getCurrentElement);

  /**
   * Return IntegrationProvider if available, otherwise just return children.
   */
  const getIntegrationProvider = () => {
    const IntegrationProvider = integrationProvider[currentElement?.type];

    return IntegrationProvider ? (
      <IntegrationProvider children={children} />
    ) : (
      children
    );
  };

  return getIntegrationProvider();
};

export default IntegrationProvider;

IntegrationProviderDaily.js

const IntegrationProviderDaily = ({ children }) => {
  const dailyRef = useRef();
  [...]

  const muteUser = (userId, device) => {
    // Do stuff
  };

  return (
    <DailyContext.Provider
      value={{
        dailyRef,
        muteUser,
      }}
    >
      {children}
    </DailyContext.Provider>
  );
};

export default IntegrationProviderDaily;

Upvotes: 1

Views: 53

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42170

The reason it totally refreshes is because you are assigning IntegrationProvider to a variable. This means that you have a different instance of the component on every render rather than the same component but with an updated value prop.

const IntegrationProvider = integrationProvider[currentElement?.type];

On another note, I am finding this code hard to read because your local variable has the same name as the component itself. That's not the cause of your problem but it is something to avoid.

You should consider having one context provider with two possible values, or having them be entirely separate. Honestly I am confused about how this is working for you. You say that the two contexts have different values. So when a child goes to access values from context, how does it know what it's getting?

Upvotes: 1

Related Questions