unstated-next icon indicating copy to clipboard operation
unstated-next copied to clipboard

Can't compose containers manually?

Open djMax opened this issue 4 years ago • 6 comments

I have a react-native app and I'm just trying to simplify the code structure slightly by changing:

export default () => (
      <LocationContainer.Provider>
        <IdentityContainer.Provider>
          <FeatureContainer.Provider>
            <SessionContainer.Provider><App /></SessionContainer.Provider>
          </FeatureContainer.Provider>
        </IdentityContainer.Provider>
      </LocationContainer.Provider>
)

To something like:

export default withRootProviders(App)

However, I get the telltale error Error: Component must be wrapped with <Container.Provider>. I don't understand what's different about it - I've tried "simple" composition (with a children prop) as well as this HOC, both fail in the same way.

type PropsAreEqual<P> = (prevProps: Readonly<P>, nextProps: Readonly<P>) => boolean;

export default <P extends {}>(
  component: {
    (props: P): Exclude<React.ReactNode, undefined>;
    displayName?: string;
  },
  propsAreEqual?: PropsAreEqual<P> | false,
  componentName = component.displayName ?? component.name,
): {
  (props: P): JSX.Element;
  displayName: string;
} => {
  function WithRootProviders(props: P) {
    return (
      <LocationContainer.Provider>
        <IdentityContainer.Provider>
          <FeatureContainer.Provider>
            <SessionContainer.Provider>{component(props)}</SessionContainer.Provider>
          </FeatureContainer.Provider>
        </IdentityContainer.Provider>
      </LocationContainer.Provider>
    );
  }

  WithRootProviders.displayName = `withRootProviders(${componentName})`;

  let wrappedComponent =
    propsAreEqual === false ? WithRootProviders : React.memo(WithRootProviders, propsAreEqual);

  return wrappedComponent as typeof WithRootProviders;
};

djMax avatar Jun 29 '20 17:06 djMax

maybe these would help

https://codesandbox.io/s/unstated-store-provider-k4h77?file=/src/store/index.js https://github.com/jamiebuilds/unstated-next#tip-1-composing-containers

olavoparno avatar Jun 29 '20 17:06 olavoparno

I saw those, but that seems like it conflates the states into one big container, no?

djMax avatar Jun 29 '20 17:06 djMax

I saw those, but that seems like it conflates the states into one big container, no?

yes, and it is left the responsibility to you to destruct what you need in order to handle component rerendering.

olavoparno avatar Jun 29 '20 17:06 olavoparno

That would cause a bunch of over-rendering, no? Or is it going to happen anyways?

djMax avatar Jun 29 '20 18:06 djMax

That would cause a bunch of over-rendering, no? Or is it going to happen anyways?

I don't remember for those examples but it might if you don't control it with useCallbacks, useMemos and memos as any other hook solution would probably. There are some solutions which come ready for this type of situations, I guess this isn't one of them.

olavoparno avatar Jun 29 '20 18:06 olavoparno

I'm just confused what the difference is between the explicit and the wrapped versions I posted. It should just be adding an entry to the hierarchy, not altering it so fundamentally.

djMax avatar Jun 29 '20 19:06 djMax