1

I have a context provider file with the code as below

contexts.tsx

import React from "react";

export const Ordering = React.createContext({
  ordering: false,
});

export const Ordering2 = React.createContext({
  ordering2: true,
});

Since I may have many more contexts, I want to combine/Compose them.

Based on the this question Too many React Context providers the code context combiner is as below

combineComponents.tsx

import React from "react";

interface Props {
  components: Array<React.JSXElementConstructor<React.PropsWithChildren<any>>>;
  children: React.ReactNode;
}

export const Compose = (props: Props) => {
  const { components = [], children, ...rest } = props;

  return (
    <>
      {components.reduceRight((acc, Comp) => {
        return <Comp {...rest}>{acc}</Comp>;
      }, children)}
    </>
  );
};

As mentioned in the solution in the question, I am trying to use this in the App as below but I get the error as shown in the picture

App.tsx

export const App = () => {

    return (
      <Compose components={[Ordering, Ordering2]}>
        <div className="app">
          <EateryInfo orderStatus={Ordering} />
          <MenuButton orderStatus2={Ordering2} />
        </div>
      </Compose>
    );
}

enter image description here

If I do not use the combiner, I use the context providers as below & it works just fine.

Can you please guide me on what is wrong. Thanks.

export const App = () => {

    const [ordering, setOrdering] = useState(false);
   const [ordering2, setOrdering2] = useState(false);
    
  const handleOrdering = () => {
    setOrdering((s) => !s);
    };
    
    const handleOrdering2 = () => {
      setOrdering2((s) => !s);
    };

    return (
        <Ordering.Provider value={{ ordering: ordering }}>
            <Ordering2.Provider value={{ ordering2: ordering2 }}></Ordering2.Provider>
        <div className="app">
          <EateryInfo orderStatus={Ordering} />
          <MenuButton orderStatus2={Ordering2} />
        </div>
      </Ordering.Provider>
    );
}
moys
  • 7,747
  • 2
  • 11
  • 42

1 Answers1

1

As you see in your last example: the context objects are not the provider components. They contain them on the .Provider property. Compose wants an array of components, so pass those:

<Compose components={[Ordering.Provider, Ordering2.Provider]}>

I also haven't seen the React.JSXElementConstructor type before, and I'd expect components to be typed as React.ComponentType; but maybe either works.

Ben West
  • 4,398
  • 1
  • 16
  • 16
  • Thanks for the answer. Your answer works. I stumbled on something similar here -> https://felixgerschau.com/react-typescript-context/ . One question though. I need to pass the `value` attribute when using the `provider`, how do I do that within `components`? I tried `, ]}>` and it does now work – moys Jan 15 '22 at 12:04
  • You won't be able to do that in your current implementation. I would modify Compose's `components` prop to accept something like `[{component: Ordering.Provider, value: orderingValue}, ...]` – Ben West Jan 15 '22 at 12:08