Skip to content

Instantly share code, notes, and snippets.

@ryanflorence
Last active October 16, 2017 15:14
Show Gist options
  • Save ryanflorence/a0b603af5a59423a45716d8f67e08844 to your computer and use it in GitHub Desktop.
Save ryanflorence/a0b603af5a59423a45716d8f67e08844 to your computer and use it in GitHub Desktop.
const SomeScreen = () => (
<div>
<Blah />
<Categories
render={categories => (
<Expenses
render={expenses => (
<div>
{groupExpensesByCategory(categories, expenses).map(category => (
<RandomScreen {...category} />
))}
</div>
)}
/>
)}
/>
</div>
)
// if it’s too noisy, pull it out into a component with some copy/paste action
const ExpensesByCategory = ({ render }) => (
<Categories
render={categories => (
<Expenses
render={expenses =>
render(groupExpensesByCategory(categories, expenses))}
/>
)}
/>
)
const SomeScreen = () => (
<div>
<Blah />
<ExpensesByCategory render={category => <RandomScreen {...category} />} />
</div>
)
@renatorib
Copy link

renatorib commented Sep 25, 2017

As I said in this tweet, you can create a compose helper similar to that one I created on react-powerplug: https://github.com/renatorib/react-powerplug/blob/master/src/utils/compose.js

In that specific case, it's will be something like this:

import React from 'react'

const compose = (elements, propNames) => {
  return ({ render }) => {

    function stackProps(i, elements, stacked = {}) {
      const childrenFn = props => i === 0
        ? render({ [propNames[i]]: props, ...stacked }) 
        : stackProps(i - 1, elements, { [propNames[i]]: props, ...stacked })

      return React.cloneElement(elements[i], {}, childrenFn)
    }

    return stackProps(elements.length - 1, elements)
  }
}

export default compose

Then, compose:

const CategoriesAndExpenses = compose(
  [<Categories foo="bar">, <Expenses foo="bar">], 
  ['categories', 'expenses']
)

const SomeScreen = ({ render }) => (
  <CategoriesAndExpenses render={({ categories, expenses }) => (
     render(groupExpensesByCategory(categories, expenses))
  )} />
)

If you find compose function ugly, you can change compose function to get prop names by element.type.name || element.type.displayName if you don't want to pass another array, but I did not recommend, since they can not be relied upon in production. Also you can change the API to pass in a different way, example:

compose([<Categories foo="bar">, 'categories'], [<Expenses foo="bar">, 'expenses'])

Etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment