(story originally appeared at kardys.dev)
A pattern that is helpful when you use external modules in your app.
Some time ago Dan Abramov posted this tweet:
Dan Abramov's tweet
<Context.Provider value={<RenderedComponent />}>
<Something />
</Context.Provider>
This pattern is neither necessary nor common, yet it is useful at certain times.
What are use cases?
The pattern is helpful when external modules arise. What exactly do I mean by external module?
See, chat. Let's assume you have SPA and you want to add Intercom-like chat to your app.
Should you setup it somewhere down in your render-tree?
It is an option.
FloatingButton.jsx
//...
<Chat
prop1={prop1}
flag
anotherFlag
/>
Yet,
What if you need a change?
- You might need it in 2+ places:
- under a floating button
- or when user selects 'help' section
- so, you instantiate 2 some components 2 times?
- You might want to keep all external configs in one place
- to have an eye on dependencies
- to slowly replace all externals with your internal code
- would looking for all of these usages be simple? It might
...but there's another way
Setup external component with context
What if instead of:
FloatingButton.jsx
//...
<Chat
prop1={prop1}
flag
anotherFlag
/>
HelpSection.jsx
//...
<Chat
prop1={prop1}
flag
anotherFlag
/>
you do:
ExternalModules
export const ExternalChatProvider = (props) => <Context.Provider value={<Chat
prop1={prop1}
flag
anotherFlag
/>}
{...props}
/>
export const ExternalChatConsumer = (props) => <Context.Consumer {...props}/>
Main
//...
<ExternalChatProvider>
<SPA/>
</ExternalChatProvider>
FloatingButton
//...
<ExternalChatConsumer/>
HelpSection
//...
<ExternalChatConsumer/>
It:
- has single point of config
- follows DRY rule
- clearly signals that module is external (read: possibly unsafe)
- rendered once
I've simplified code, but you could:
- add memoization,
- parametrize it,
- etc.
This technique is useful not only for external modules, but for using shared components in general.
A word of caution: do not overuse
- context is additional component,
- it causes jumps in logic and
- it is harder to read app flow with to many contexts.
How do you manage external components?
Top comments (0)