Recompose: Is there a more efficient way to namespace the result of a series of HoCs than collecting parent props then spreading them back in?

Created on 12 Apr 2017  路  8Comments  路  Source: acdlite/recompose

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

enhancement

Most helpful comment

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 }))
)

All 8 comments

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.

  • Only specified outer props will pass into the scope.
    (Specify by consumProps or injectProps)
  • Only specified inner props will send to the base component.
    (Specify by passProps or passHandlers)
  • All outer, not consumed props will skip the scope and pass through to the base component.
  • Injected outer props will still send to the base component.
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/setPropTypes
  • injectProps receives the same paramater as recompose/setPropTypes
  • passProps receives the same paramater as recompose/withProps
  • passHandlers receives the same paramater as recompose/withHandlers

Problem 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.
      }
  }
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

jeron-diovis picture jeron-diovis  路  4Comments

xialvjun picture xialvjun  路  4Comments

SeanGroff picture SeanGroff  路  4Comments

gajus picture gajus  路  4Comments

Secretmapper picture Secretmapper  路  3Comments