This pattern is for those of you that maintain multiple applications and need to build components that can be reused across all these apps. It won’t be useful if you build components meant to be reused in the same application.
If you use smart/dumb, or container/presentational components, which you should if you want your components to be at least a little reusable, your typical application might look like this:
const AppElement = (
<App>
<Container1>
<Reusable1/>
<Reusable2/>
<ComplexReusableComponent>
<Reusable3>
<Reusable4>
<VeryDeeplyNestedReusable/>
</Reusable4>
</Reusable3>
</ComplexReusableComponent>
</Container1>
<Container2>
...
<Container2>
</App>
)
Some components, like ComplexReusableComponent
are high-level, and compose multiple lower-level components, like VeryDeeplyNestedReusable
.
These 2 kinds of components are supposed to be reused across multiple apps your are building.
A new requirement comes in, and you have to change the behavior of VeryDeeplyNestedReusable
according to some data you hold in state of one of your app.
This is really annoying us, because this component is very deeply nested and used in multiple high-level components. By using props passing, you will likely need to modify a lot of components just to bring this little change.
To solve this, Redux has connect(), and it avoids you to pass the data your component need into every intermediate component.
Unfurtunatly, you don't have a single application, but multiple ones.
Some of them use Redux, and some don't. Some might even use another legacy Flux framework.
Some of them only use VeryDeeplyNestedReusable
, and some of them also use high-level components like ComplexReusableComponent
You can't connect VeryDeeplyNestedReusable
for all apps because it won't work for apps that don't have a Redux store in context. Even if they all had a store, the state shape might not be the same anyway...
But still, using props passing is really annoying you.
Inject an app identity into React context:
App1 = provide("app1")(App1);
App2 = provide("app2")(App2);
App3 = provide("app3")(App3);
Do component branching according to the context:
VeryDeeplyNestedReusable = branchByAppIdentity({
"app1": VeryDeeplyNestedReusable,
"app2": connect(state => state.someData)(VeryDeeplyNestedReusable),
"app3": OtherFlux.injectData(VeryDeeplyNestedReusable),
});
It can also be useful, if you want the component to look very differently according to the context (can be compared to theming):
const VeryDeeplyNestedReusable = branchByAppIdentity({
"app1": (props) => <div>Variation1</div>,
"app2": (props) => <div>Variation2</div>,
"app3": (props) => <div>Variation3</div>,
});
Not sure but I guess it could also be useful for ReactNative (I don't know RN):
const VeryDeeplyNestedReusable = branchByAppIdentity({
"web": (props) => <div>Text web</div>,
"ios": (props) => <View>Text iOS</View>,
"android": (props) => <View>Text Android</View>,
});
Yes, by using this trick, your component became a bit less reusable.
The difference is that using something like Redux connect() couples the component to a specific app, while this trick only couples the component to your company. You can still use easily the component across multiple apps in the same company. If you are building a real product, and not a react-bootstrap lib, it should be fine!