Is there a more efficient way to namespace a series of HoCs than this? (credits to my friend @jephuff for the below solution)
const namespace = (ns, ...hocs) => compose(
Wrapped => (props) => Wrapped({ parentProps: props }),
...hocs,
Wrapped => ({ parentProps, ...props }) => Wrapped({ ...parentProps, [ns]: props })
);
// example usage:
compose(
withProps({a: 10, b: 11, c: 12}),
namespace(
'namespace',
withProps({a: 1, b: 2, c: 3}),
),
)((props) => <pre>{JSON.stringify(props, null, ' ')}</pre>)
renders
{
"a": 10,
"b": 11,
"c": 12,
"namespace": {
"a": 1,
"b": 2,
"c": 3
}
}
Here's a pen: http://codepen.io/cheapsteak/pen/OmJWKZ?editors=0010
Not sure it's more efficient but IMO more readable:
const namespace = (ns, ...hocs) => compose(
withProps(props => ({ $parentProps: props })), // TODO $parentProps as symbol
...hocs,
mapProps(props => ({ [ns]: props, ...props.$parentProps }))
)
Also nice idea, will try in my projects. cc @wuct
I can't come up with other solution. Using Symbol looks good to me.
Not sure if a module I wrote was helpful. Just put it to a repo compose-with-scope(feedback wanted!!)
Use it to rewrite the @cheapsteak's example will like below
compose(
withProps({a: 10, b: 11, c: 12}),
composeWithScope(
withProps({a: 1, b: 2, c: 3}),
passProps(props => ({ namespace: props })),
),
)((props) => <pre>{JSON.stringify(props, null, ' ')}</pre>)
Using composeWtihScope with consumeProps, injectProps, passProps and passHandlers can manage the inner props and outer props of a compose scope and avoid prop name collision.
consumProps or injectProps)passProps or passHandlers)const consumeRoute = composeWithScope(
consumeProps({
location: propTypes.object,
match: propTypes.object,
history: propTypes.object,
}),
passProps(({ location, match }) => ({
path: location.pathname,
view: match.params.view,
id: match.params.id,
})),
passHandlers({
redirectToMenu: ({ history }) => () => history.push('/menu'),
}),
)
consumeProps receives the same paramater as recompose/setPropTypesinjectProps receives the same paramater as recompose/setPropTypespassProps receives the same paramater as recompose/withPropspassHandlers receives the same paramater as recompose/withHandlersProblem with these solutions is that nesting namespace hocs breaks it, as they all depend on the same parentProps key. Using a symbol would work, except some hocs will not copy over symbols depending on how they pass props, so there is no guarantee your symbol will be accessible out the other side :(
A way to make nesting work is to also pass a $parentPropsNestLevel prop that you increment and decrement at either end, and then your $parentProps becomes: $parentProps2, where 2 is the nesting level
My final solution has a __scopes array that I simply push and pop to and from 馃憤
The same parentProps key shouldn't be an issue unless you need to access it
example: https://codesandbox.io/s/6xjxqwowoz
you will end up with
{
parentProps: {
parentProps: {
// the parent props.
}
}
}
Most helpful comment
Not sure it's more efficient but IMO more readable: