How To Pass Props to {react.children} - React FAQ

💡 Quick Solution: use React.cloneElement to create a new component with the parent's props.

  • Create the Parent component
export function Layout(props) {
  return (
    <div>
      {React.Children.map(props.children, (child) =>
        React.cloneElement(child, props)
      )}
    </div>
  );
}
  • Use it to render children. <OtherReactComponent/> now has access to props of <Layout/>.
const App = () => (
  <Layout isAuthenticated={true}>
    // <OtherReactComponent /> has access to isAuthenticated prop
    <OtherReactComponent />
    <OtherReactComponent />
    <OtherReactComponent />
  </Layout>
);

Diving Deeper

Everyone knows how to pass props to react components, but your case is different. You don't really know the component you'll pass as a child/children and you want them to inherit the parent's props. A good use case might be a <Protected/> component. You'll want every child of the component to have access to an isAuthenticated prop. You've even tried something like this...

export function Layout(props) {
  return <div>{props.children(props)}</div>;
}

As you know, this doesn't work.

Pass Props to React.Children Errors

Why doesn't {props.children(props)} work?

There's a couple of reasons why, but the most important is that react.children isn't a function and can't be called with arguments (It's possible, but it's just safe to think of it as not).

In fact, it helps to think that React components can only receive the following as valid children...

// A string as child
<Component>String Child</Component>

// Another React component
<Component>
  <SomeReactComponent/>
</Component>

// Array of react components
<Component>
  <SomeReactComponent/>
  <SomeReactComponent/>
  <SomeReactComponent/>
</Component>

// A combination of the above
<Component>
  <SomeReactComponent/>
  <SomeReactComponent/>
  Something Else
</Component>

This means we have to pass any of these as children to a component.

Possible Solutions

There are many ways to solve this problem today, but we'll stick to these 2

  1. React.cloneElement
  2. Context API

React.cloneElement

React.cloneElement creates a new component from an already existing one. The syntax looks something like this...

React.cloneElement(Component, { ...componentProps });

You'll also want to wrap it in a map function so it handles the case of multiple React components. See the documentation for more about React.Children.

export function Layout(props) {
  return (
    <div>
      {React.Children.map(props.children, (child) =>
        React.cloneElement(child, props)
      )}
    </div>
  );
}

Context API

What if we thought of the problem differently? If your goal is to share props with a component's children, then the Context API is the best solution. You don't have to manually pass props around like some lunatic 🏃🏼‍♀️🏃🏼‍♀️🏃🏼‍♀️. Say yes to clean code!

How to use the Context API

I'm trying to keep this article short, so I'll breeze over concepts and assume you have experience with the context API. If not, you might want to learn about it and why you need it first.

  • Wrap the parent component in a Provider
import { createContext } from "react";
export function Layout(props) {
  const LayoutContext = createContext(null);

  return (
    <LayoutContext.Provider value={props.isAuthenticated}>
      <div>{props.children}</div>
    </LayoutContext.Provider>
  );
}
  • Access the values in the child Component with the useContext hook
import { useContext } from "react";
export function ChildComponent(props) {
  const layoutContextValue = useContext(LayoutContext);

  const { isAuthenticated } = layoutContextValue;

  if (!isAuthenticated) {
    // do something when user isn't loggedIn
  }

  return (
    <div>
      <SomeOtherComponent />
    </div>
  );
}
  • Use in your app
export function App() {
  return (
    <Layout isAuthenticated={true}>
      <ChildComponent />
    </Layout>
  );
}

I hope this post helped you solve your bug. Please reach out to me on Twitter if there's something I'm missing. I'll be glad to edit accordingly.

More Resources

Happy debugging ğŸŽˆ