Security News
Supply Chain Attack Detected in Solana's web3.js Library
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
react-composition-provider
Advanced tools
A High Order Component library for components to follow the Composition Provider pattern
react-composition-provider
is a small react library that helps you implement a Composition Provider pattern.
The Composition Provider pattern tries to make prop drilling more ergonomic.
npm i --save react-composition-provider
Let's look at a simple example of Menu
, Card
, CardList
, NewsList
& WeatherList
components.
Where CardList
contains Card
and Card
contains Menu
.
Where NewsList
& WeatherList
both contain CardList
.
We want to pass props from NewsList
& WeatherList
to Menu
, this is how you do it:
// Menu.js
import { withCompositionProvider } from 'react-composition-provider';
const InnerMenu = ({ cardId, items }) => {
// This is where the actual menu code would be.
};
export default withCompositionProvider(InnerMenu);
// Card.js
import Menu from './Menu';
export default (props) => {
return (
<div>
<Menu cardId={props.id}/>
</dib>
)
}
And in NewsList
& WeatherList
you'd do this:
// NewsList.js
import Menu from 'Menu';
export default (props) => {
const actions = [{ text: 'remove' }, { text: 'star' }];
return (
<Menu.Provider items={actions} >
<CardList cards={props.news}/>
</Menu.Provider>
)
}
// WeatherList.js
import Menu from 'Menu';
export default (props) => {
const actions = [{ text: 'remove location' }];
return (
<Menu.Provider items={actions} >
<CardList cards={props.locations}/>
</Menu.Provider>
)
}
And that's it!
Now every time you want to supply extra props to a decendant Menu
component just render Menu.Provider
with what you need!
This is the basic usage but the library gives you a lot more features than just this, like:
Menu.Provider
in the same tree, that way even if someone is using Menu.Provider
in a component you can't change you'll still be able to pass more props to it!Menu.Provider
can add props you can use Menu.Provider.Scoped
.<Menu.Provider ref={...}
and get the ref of the provider, right?ref
, style
, className
and children
) and gives you a way to define the composition for each prop.kids
because obviously the children
prop is already taken.Menu
was rendered somewhere, it doesn't mean that InnerMenu
has to be mounted.Menu.Provider
and which aren't.Most of these can be configured through a second options argument to withCompositionProvider
:
import { withCompositionProvider, composers } from 'react-composition-provider';
export default withCompositionProvider(MyComponent, {
// Object defining all the polyfills used by this package.
polyfills: {
// If you're using an old version of react that doesn't have React.createContext,
// you'll need to supply a polyfill for it, something like - https://github.com/jamiebuilds/create-react-context
createContext: React.createContext
}
// Allows you to control when the inner component actually mounts.
// Returns true if the component should mount and false when it shouldn't.
// props - all the composed props for this component
// propsChain - an array of props, ordered by closeness to the actual component.
// where propsChain[0] is given directly to the component and propsChain[1] is the closest Provider, and so on.
mountWhen: ({ props, propsChain }) => true,
// An array of props to ignore from all the Providers up the chain.
ignore: [],
// The most advanced configuration.
// Gives you full control over the composition of each and every prop.
// Each key in this object is the prop name and the value is a function that composes it and returns said composition.
// Luckily, you don't have to think about it too much because react-composition-provider comes with a built-in set of composers.
// To use these composers just import it like this:
// import { composers } from 'react-composition-providers';
//
// There are 2 available variations for some of the composers, reverse or take.
// reverse - composes the same way but just in reverse order.
// take - an object with first, last & index that takes a single element from the array.
// Note that all of the composers implement the take capabiliy, the ones marked with reverse can also use that capability.
//
// These are the available composers:
// 1. composers.node() - combines an array of nodes as siblings using React.Fragment. (reverse)
// 2. composers.string(separator: String) - combines an array of strings with the given separator (defaults to " " - space). (reverse)
// 3. composers.object(merge: (objects: Array<Object>) => Object) - combines an array of objects by merging them together.
// the first one is the least specific and the last is the most specific.
// the merge callback takes in an array of objects and returns a merged object (defaults to Object.assign). (reverse)
// 4. composers.array() - combines an array of arrays to a single array (essentially a flatMap). (reverse)
// 5. composers.func.result.compose(composer: Composer) - executes each function in the array sequentially, the composer parameter is used to combine the results.
// 6. composers.func.result.ignore() - executes each function in the array sequentially and ignores the result.
// 7. composers.bool.and() - combines an array of booleans to a single boolean value by "&&" all of them together.
// 8. composers.bool.or() - combines an array of booleans to a single boolean value by "||" all of them together.
// 9. composers.number.sum() - gets the sum of the array of numbers.
// 10. composers.number.min() - gets the minimum number of the array of numbers.
// 11. composers.number.max() - gets the maximum number of the array of numbers
// 12. composers.number.average() - gets the average of the array of numbers.
// 13. composers.date.min() - gets the minimum date of the array of dates.
// 14. composers.date.max() - gets the maximum date of the array of dates.
compose: {},
});
As you can see this API is very flexible, but tries to have sane defaults.
Prop drilling makes our components too specific, and tie the API of a component with the components it's composing (its implementation).
When these components change it will probably mean that the API will change too.
This applies to all the levels you "drill" the props, if something way down the line changes - all of them change.
What happens when you forget to drill some props? that's a tedious job of going through all the levels between where you have the prop value all the way down to the where it actually needs to be.
You might say that you can solve all of that with a state management library like redux
- that's true.
You'd then need to define reducers, actions, and connect components to a store - just to pass some props down the line. It's like using a hammer for screws.
That's why react-composition-provider
exists.
It creates a "portal" between the component itself and all the places you defined props for it.
It's very small (6kb non-gzipped) so you won't feel it, plus it'll probably help you save some boilerplate code so you code end up with a smaller bundle!.
Although this pattern can be very helpful and you're maybe thinking to yourself "I'm going to define all of my components like this now!".
JUST DON'T
General rules of thumb (there are probably more since this is new) of dos and don'ts with this pattern:
xxxProps
- you already want to expose the props for xxx
as part of your API.So, as with all patterns out there - make sure you understand what you're doing and don't abuse it.
MIT
FAQs
A High Order Component library for components to follow the Composition Provider pattern
We found that react-composition-provider demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
A supply chain attack has been detected in versions 1.95.6 and 1.95.7 of the popular @solana/web3.js library.
Research
Security News
A malicious npm package targets Solana developers, rerouting funds in 2% of transactions to a hardcoded address.
Security News
Research
Socket researchers have discovered malicious npm packages targeting crypto developers, stealing credentials and wallet data using spyware delivered through typosquats of popular cryptographic libraries.