add prop value and property to all children

Viewed 86

I want to pass a prop value to all of a components current children, however I feel it's a little tedious to do it to each and every single child component (especially if you have a considerable amount). I initially thought a context would suffice, but I came across the same issue of adding a considerable amount of boilerplate code that could otherwise be extremely simple.

Is there anything within React that could achieve the same affect as:

<Parent>
    <ChildOne propForAllChildren={this.state.example} />
    <ChildTwo propForAllChildren={this.state.example} />
    <ChildThree propForAllChildren={this.state.example} />
</Parent>

With something like this:

<Parent passPropsToChildren={{"propForAllChildren": this.state.example}}>
    <ChildOne />
    <ChildTwo />
    <ChildThree />
</Parent>

There's nothing in the documentation which I can find, and I could very easily create a component which would do exactly this. But, why reinvent the wheel if it already exists?

4 Answers

In this case I usually look the problem on children side. Let me explain better: you know that all Child will have a prop called propForAllChildren and most probably this prop is always at the same value. Well, on Child put a default value for that prop so you could avoid to pass it:

<Parent>
    <ChildOne />
    <ChildTwo />
    <ChildThree />
</Parent>

export default function ChildOne(props) {
    const { propForAllChildren = true } = props;
    ...
}

And the same thing for the other Child.

Yes, this line const { propForAllChildren = true } = props; will be the bolierplate but I think is a minimum price to pay.

You can create a HOC DispatchPropsToChildren to do this functionality. The purpose of this HOC component is to loop between children and injecting to them the props.

function DispatchPropsToChildren({ propsToDispatch, children }) {
  return (
    <>{children.map(child => cloneElement(child, { ...propsToDispatch }))}</>
  );
}

How to use it:

Component App:

export default function App() {
  return (
    <Parent>
      <DispatchPropsToChildren propsToDispatch={{ propOne: 1, propTwo: 2 }}>
        <ChildOne />
        <ChildTwo />
      </DispatchPropsToChildren>
    </Parent>
  );
}

Component Parent:

function Parent({ children }) {
  return children;
}

Component ChildOne:

function ChildOne(props) {
  console.log(props);
  return <div>ChildOne</div>;
}

Component ChildTwo:

function ChildTwo(props) {
  console.log(props);
  return <div>ChildTwo</div>;
}

You can check this demo: https://stackblitz.com/edit/react-xqmevc

hi this is the solution

import React,{useState , useEffect} from 'react';


const ChildOne = (props) => {
  console.log(props);
  return(
    <p> ChildOne </p>
  )
}


const ChildTwo = (props) => {
  console.log(props);
  return(
    <p> ChildTwo </p>
  )
}


const ChildThre = (props) => {
  console.log(props);
  return(
    <p> ChildThre </p>
  )
}


const Parent = ({ children,passPropsToChildren }) => {

  const [ propedChilds , setPropedChilds ] = useState([]);

  useEffect(() => {
    if(passPropsToChildren){

      const childrenWithProps = React.Children.map(children, child => {
        if (React.isValidElement(child)) {
          return React.cloneElement(child, {
            ...passPropsToChildren
          });
        }
        return child;
      });

      setPropedChilds(childrenWithProps);
      
    }
  }, [children,passPropsToChildren]);

  return(
    <>
      {propedChilds}
    </>
  )

}

const App = () => {

  return(
    <Parent passPropsToChildren={{ "propForAllChildren": true }}>
      <ChildOne />
      <ChildTwo />
      <ChildThre />
    </Parent >
    )
}

As it stands, there seems to be no official iterable prop component such as the one defined. So I went to my own devices to create a very basic implementation of one - just in case anyone deems it useful - feel free to use or alter.

Hopefully one day the React team will add similar functionality to a future version of React.

const PropsToChildren = React.memo(({ props, children }) => (
    <Fragment>
        { children.map((child) => React.cloneElement(child, {...props})) }
    </Fragment>
));

// it can be used as such
<PropsToChildren props={{propA: propAValue}}>
    { /* children go here... */ }
</PropsToChildren>

// and it will output the following
<ChildOne propA={propAValue} />
<ChildTwo propA={propAValue} />
// etc...
Related