React - How to pass props to a component passed as prop

39,139

Solution 1

You can achieve that by using React.cloneElement.

Like this:

class CustomForm extends React.Component {
  ...
  render() {
    return (
      <div>
          {React.cloneElement(this.props.component,{ customProps: this.props.object })}
      </div>
    );
  }
}

Working Code:

class Parent extends React.Component{
  render() {
    return(
      <Child a={1} comp={<GChild/>} />
    )
  }
}
class Child extends React.Component{
  constructor(){
    super();
    this.state = {b: 1};
    this.updateB = this.updateB.bind(this);
  }
  updateB(){
    this.setState(prevState => ({b: prevState.b+1}))
  }
  render(){
    var Comp = this.props.comp;
    return (
      <div>
        {React.cloneElement(Comp, {b: this.state.b})}
        <button onClick={this.updateB}>Click to update b</button>
      </div>
    );
  }
}
const GChild = props => <div>{JSON.stringify(props)}</div>;
ReactDOM.render(
  <Parent />,
  document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='container' />

Solution 2

You can do in the same as you did for SomeInnerComponent.

Just pass named props.

Inside CustomForm,

render() {
  const MyComponent = this.props.component; //stored it in some variable
    return (
      <div> 
         <MyComponent customProps = {this.props.object} /> //access object here and passed it or passed individual props
      </div>
    );
  }

EDIT :

Please find the working demo here.

Solution 3

You have a couple of options to achieve what your asking.

class SomeContainer extends React.Component {
  ...
  render() {
   let someObjectVariable = {someProperty: 'someValue'};
    return (
      <CustomForm 
       component={<SomeInnerComponent propFromParent={someObjectVariable}/>}
       object={someObjectVariable}
      />
    );
  }

}

Or you can clone the component prop and apply the new props as Mayank said. In your case

class CustomForm extends React.Component {
  ...
  render() {
    return (
      <div>
        {React.cloneElement(this.props.component,
           {propFromParent:this.props.someObjectVariable})}
      </div>
  );
 }
}
Share:
39,139

Related videos on Youtube

Author by

Daniel Calderon Mori

Updated on July 09, 2022

Comments

  • Daniel Calderon Mori 12 months

    I have a React component (React v15.5.4) that you can pass other components to:

    class CustomForm extends React.Component {
      ...
      render() {
        return (
          <div>
              {this.props.component}
          </div>
        );
      }
    }
    

    And I have a different component that uses it:

    class SomeContainer extends React.Component {
      ...
      render() {
        let someObjectVariable = {someProperty: 'someValue'};
        return (
          <CustomForm 
             component={<SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>}
             object={someObjectVariable}
          />
        );
      }
    }
    

    Everything renders fine, but I want to pass someObjectVariable prop to the child component inside CustomForm (in this case that'll be SomeInnerComponent), since in the actual code you can pass several components to it instead of just one like the example.

    Mind you, I also need to pass SomeInnerComponent its own props.

    Is there a way to do that?

    • Arnold Gandarillas
      Arnold Gandarillas over 5 years
      which one do you refer when you said child component CustomForm or SomeInnerComponent?
    • Daniel Calderon Mori over 5 years
      @ArnoldGandarillas SomeInnerComponent. I'll edit my question
    • Daniel Calderon Mori over 5 years
      Yes, I'm aware that's one way. But like I said, I might pass an array of several components, and I don't want to do that for each one
    • Arnold Gandarillas
      Arnold Gandarillas over 5 years
      If you are going to pass a many components with a shared value won't be better if you use context? In this way you'll avoid to recreate the components over and over again
  • Daniel Calderon Mori over 5 years
    Got this error message when I tried this approach: "Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object"
  • Daniel Calderon Mori over 5 years
    I can't use option 2 because I need to pass SomeInnerComponent its own props. I'll edit to question to make that clear. I'll try 1 though
  • Mayank Shukla
    Mayank Shukla over 5 years
    oh ok, if you want to use the 2nd approach, then you can do one thing. Pass all those props values to CustomForm then from CustomForm you can pass to SomeInnerComponent.
  • Daniel Calderon Mori over 5 years
    Will child props passed from CustomForm be updated if value changes on CustomFor? doesn't look like it does
  • RIYAJ KHAN
    RIYAJ KHAN over 5 years
    @DanielCalderonMori It should be work.I think inside . of your SomeInnerComponent or CustomForm you are trying display an object that why you getting such error.Please see updated DEMO codedandbox
  • Daniel Calderon Mori over 5 years
    It does, there was something wrong with my code. So if you just leave option 1, I can check this as the correct answer. And thanks a lot for your help.
  • RIYAJ KHAN
    RIYAJ KHAN over 5 years
    As I mentioned with keyword working demo here. replace myComponent and myComponent with component and SomeInnerComponent resp. :D
  • Arthur Tacca
    Arthur Tacca over 4 years
    This works if you pass someInnerComponent=SomeInnerComponent i.e. you are passing a class, but not if you pass someInnerComponent={<SomeInnerComponent someProp={'someInnerComponentOwnProp'}/>} i.e. passinig an object, which is what the question was asking about. With this technique you have no way to set some props at the top level and some more at the mid-level container, you have to set them all in the mid-level container.