A frequent (and IMO poor) design pattern I come across in React code are higher order components that do not propagate props to their children:
// No option to pass props to sub-components!
return (
<SomeHOC
componentOne={ComponentOne}
componentTwo={ComponentTwo} />
);
I often want to pass props to these subcomponents. The simplest method is to define a nested component, but this component will be unstable:
function MyComponent({ prop1, prop2 }) {
// Unstable!!!
const WrappedComponentOne = (props) => (<ComponentOne prop1={prop1} {...props} />);
return (
<SomeHOC
componentOne={WrappedComponentOne}
componentTwo={ComponentTwo}
/>
);
}
You can create a static wrapper, but that only lets you pass in props you know in advance:
function WrappedComponentOne(props) {
// No way to pass data from MyComponent!
return <ComponentOne staticProp="value" {...props} />;
}
function MyComponent({ prop1, prop2 }) {
return (
<SomeHOC
componentOne={WrappedComponentOne}
componentTwo={ComponentTwo}
/>
);
}
The only working solution I have, which seems fairly obtuse, is to use a provider:
export const MyContext = createContext({});
function WrappedComponentOne(props) {
const myProps = useContext(MyContext);
return <ComponentOne {...myProps} {...props} />;
}
function MyComponent({ prop1, prop2 }) {
return (
<MyContext.Provider value={{prop1}}>
<SomeHOC
componentOne={WrappedComponentOne}
componentTwo={ComponentTwo}
/>
</MyContext.Provider>
);
}
My question is, if I do not control the HOC or sub-components, is there a better way to do this?
Using Context is the proper way to pass properties from some arbitrary parent component to some arbitrary child component regardless of tree depth. It allows child to consume known data without passing that data through the whole sub-tree, which can lead to large amount of maintenance and potential errors. For example, you are passing property “myProp”. Something changes and somewhere between your parent and your child there is a new component that also consumes “myProp”. This can have two outcomes. First, your child will not get the property at all. Second, your child will receive incorrect data. Context saves you from both those cases along with needing to pass props through everythin “just in case”.