React Komposer pass props to all children


#1

I have an AppContainer which subscribes to UserAccount that publishes custom fields in users document like md5hash, stripe plan, etc. which I couldn’t just get through Meteor.user(). The AppContainer sends props to AppLayout where it has Header and I can send user props to it and it works fine. However, I want to send user props to the children components of AppLayout.

One more question. Is having an AppContainer okay? Instead of making containers just to get some user informations in different part of the app. If not, is there an easier way to get the extra (custom) fields of users document?

AppContainer:

import React from 'react'
import { composeWithTracker } from 'react-komposer'

import { AppLayout } from '../layouts/AppLayout'

const composer = (props, onData) => {
  const subscription = Meteor.subscribe('userAccount')

  if(subscription.ready()) {
    const user = Meteor.users.findOne({ _id: Meteor.userId() })
    onData(null, { user })
  } else {
    onData(null, { loading: true })
  }
}

export default composeWithTracker(composer)(AppLayout)

AppLayout:

import React from 'react'

import { Header } from '../components/header/Header'

export const AppLayout = ({ children, user }) => (
  <div className="app-layout">
    <header>
      <Header user={ user } />
    </header>
    <main>
      { children } {/*<---- I want to send user prop here */}
    </main>
    <footer>
    </footer>
  </div>
)

#2

You can map over the children with React.Children and clone them with parent props using React.cloneElement like so:

import React, {Children, cloneElement} from 'react'
import { Header } from '../components/header/Header'

export const AppLayout = ({ children, user, ...props }) => (
  <div className="app-layout">
    <header>
      <Header user={ user } />
    </header>
    <main>
      { Children.map( children, child => cloneElement(child, {...props}) ) } 
    </main>
    <footer>
    </footer>
  </div>
)

this is a solution for the immediate children. If you want, you can take the props provided by the composer and place them in the context. In that case, any children deep in the structure will also have access to them within the context, but I guess it is not something you’d structure your app for.


#3

Thanks, it worked perfectly.

But I’m wondering, now that I’m sending user data props to every children of AppLayout, is it better to send props to specific child component? If so, how would I do that?

I’m using react-router, and I was wondering if it’s possible to make a route container that subscribes to user data and pass it down to only some components… I don’t know what I’m really asking, just looking for alternatives to above solution.


#4

You can compose specific children themselves, or use a global state store like redux and subscribe to it (that too works like a composer) from the components that need those props.


#5

In general it is not a good idea to show all props of a parent, X, to all children of X. This could get messy with prop names, things getting overridden in the chain, etc. You can manually pass props down the chain, or you can use React’s context to make it slightly easier to pass information from parents to children. Props are meant to be explicit properties of the component in question. The context architecture allows you to explicitly refer to dynamic variables owned by parents without overriding subcomponents props.