9

I have a child component in a Layout that I want to pass a props value too. But I don't know how. In the class below the layoutFileDataRequest() receives a string variable from a child component on a click event. There is a need to send that value to one of the this.props.children components so it can update.

How do I do this? In the code below React.cloneElement(child, { does not change it always stays the same which means I can't update the child prop.

  export default class Layout extends React.Component {
    constructor(props) {
      super(props)

      this.layoutFileDataRequest = this.layoutFileDataRequest.bind(this);
      this.state = {
        newData: '',
        returnData: 'test',

      }
    }

    /**
     *  Received request from server add it to 
     *  react component so that it can be rendered
     */
    layoutFileDataRequest(data) {
      this.setState({ returnData:data })
    }


    renderChildren() {
      return React.Children.map(this.props.children, child => {
        console.log(this.state.returnData); 
          return React.cloneElement(child, {
            data: this.state.returnData
          })
      });
    } 

    /**
     *  Render request
     * 
     * 
     */
    render() {
      const { location } = this.props;
      const title = this.state.newData;
      return (
        <div id="app-container" class={title}>
          <Nav location={location} />
          <main id="main">
            <h1>{title}</h1>
            <section>
                {this.renderChildren()}
            </section>
          </main>
          <Project layoutFileDataRequest={this.layoutFileDataRequest} />
          <Footer />
        </div>
      );
    }
  }


export default class Project extends React.Component {
  constructor(props) {
    super(props)

    this.projectFileDataRequest = this.projectFileDataRequest.bind(this);

    this.state = {
      newData: [],
    }

  }


  /**
   *  Received request from server add it to 
   *  react component so that it can be rendered
   */
  projectFileDataRequest(data) {
    this.props.layoutFileDataRequest(data);
  }


  /**
   *  Received request from server add it to 
   *  react component so that it can be rendered
   */
  componentDidMount() {
    ApiCalls.readSassDirData()
      .then(function (serverData) {
        this.setState({ newData: serverData[0].data })
      }.bind(this));
  }


  /**
   *  Render request
   */
  render() {
    const listOfObjects = this.state.newData;
    return (
      <aside id="project">
        <h2>Files</h2>
        <FileListing listOfObjects={listOfObjects} projectFileDataRequest={this.projectFileDataRequest} />,
       </aside>
    );
  }
}
purencool
  • 423
  • 7
  • 17
  • The way you passing props to children component looks all good in `renderChildren`. Your child component should be able to access `data` by `this.props.data`. Please refer to https://stackoverflow.com/questions/32370994/how-to-pass-props-to-this-props-children on passing props to children. Not sure what do you mean ? – Kevin Li Apr 28 '18 at 05:19
  • Thanks in the code above React.cloneElement(child, { does not change it always stays the same – purencool Apr 28 '18 at 05:51
  • Can you share `Project `code – Liam Apr 28 '18 at 06:18
  • I have just added it above or you can see it here https://github.com/purencool/purencool_editor/blob/master/src/js/components/layout/Project.js – purencool Apr 28 '18 at 06:26
  • 1
    So now I'm in `ide/FileListing` file why you are doing this `changeValue = (data) => (e) => {` – Liam Apr 28 '18 at 06:37
  • Also I'm seeing you forgot to bind changeValue function, change it like this `{dataObj.file_name}` – Liam Apr 28 '18 at 06:39
  • It passes the value up to project props then project the passes props up to layout and I want layout to pass it down to the child ide. It might be the wrong way to do it. I new to react. =) Thanks for looking a it. – purencool Apr 28 '18 at 06:40
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/169977/discussion-between-liam-and-purencool). – Liam Apr 28 '18 at 06:41
  • Do you have an example of the props – Nick Prozee May 01 '18 at 10:08
  • Your code works, check this https://codesandbox.io/s/ppr2k331jj, there might be some issue with how you are handling the data or rendering it – Shubham Khatri May 01 '18 at 18:26
  • @purencool, let me know if the codesandbox that I linked doest help you – Shubham Khatri May 02 '18 at 06:09

3 Answers3

4

I think the error is in the renderChildren function.

Code

 renderChildren() {
      return React.Children.map(this.props.children, child => {
        console.log(this.state.returnData); 
          return React.cloneElement(child, {
            data: this.state.returnData
          })
      });
    }

New Code

renderChildren(){
    return this.props.children.map(child => 
        React.cloneElement(child, { 
            data: {...this.state.returnData }
        })
    );
}
Nick Prozee
  • 2,823
  • 4
  • 22
  • 49
  • 1
    Thanks for the reply I have added what you suggested and this is the error in the browser console `TypeError: this.props.children.map is not a function` – purencool May 01 '18 at 22:14
  • @NickProzee, the original code is actually correct. and is the recommended way – Shubham Khatri May 02 '18 at 06:09
0

There's nothing wrong with the actual code, the only thing that i am guessing is happening is that in the <FileListing /> component there is not and invocation to the prop (method) projectFileDataRequest passing the update that wants to be transfer it to the <Layout />'s children.

TL;DR... Here is your code working and updating the <Layout />'s children just after receiving a click event in <FileListing />.

https://codesandbox.io/s/5050w0p9kx

I hope it helps you

-1

Your code actually works fine. This is cloneElement's arguments:

React.cloneElement(
  element,
  [props],
  [...children]
)

You are passing data as props to child components.

Check this out: stackblitz.com/edit/react-xhwmd3?file=Layout.js

kursat
  • 1,059
  • 5
  • 15
  • 32