2

There are some question relative, but completely different

Call child method from parent

Call child function from parent component in React Native

https://github.com/kriasoft/react-starter-kit/issues/909

They all need import Child in Parent file.

But how to set ref to this.props.children ???

Purpose

I want to call Child method in Parent , Parent is a common wrapper which require a Child with specific function . Child is dynamic,

  1. Child

    class Child extends React.Component {
      method() {
        alert(1111);
      }
      render() {
    
        return (
          <div>
            ....
          </div>
        );
      }
    }
    
  2. Parent

    import React from 'react'
    // can not import Child here
    // import Child from './Child'  
    
    class Parent extends React.Component {
      onClick = () => {
        this.props.children.method() // do stuff, but not work
      }
      render() {
    
        const {children} = this.props;
        return (
          <div>
            {children}
            <button onClick={this.onClick}></button>
          </div>
        );
      }
    }
    
  3. index.js

    <Parent>
       <Child/ >
    </Parent>
    

Parent only can access Child by this.props.children, I don't want pass Child's method to Parent in index.js , or define Child's method in index.js.

In other word:

  1. Child keep all Child's code.(For example, a form with submit logic)

  2. Parent is a common wrapper. (For example, a dialog used to wrap a form)

  3. Index.js don't care them

Any idea?

Mithril
  • 12,947
  • 18
  • 102
  • 153
  • Is `children` an single child in your case. If its so then, its quite easy. If its multiple, then you have to find which one it it.. – Panther Sep 12 '17 at 09:42
  • It is single. I had tried `this.props.children.handleSubmit()`, but not work. So I ask this question. – Mithril Sep 12 '17 at 09:43
  • 1
    You can use `React.cloneElement` and pass an `ref` to it. Then you can use the ref to access the function from parent. – Panther Sep 12 '17 at 09:48

3 Answers3

2

Thanks to @Panther 's comment, I work it around by using React.cloneElement :

  1. Child

    class Child extends React.Component {
    
      handleSubmit() {
        //...
      }
    
      render() {
    
        return (
          <div>
            ....
          </div>
        );
      }
    }
    
  2. Parent

    import React from 'react'
    
    class Parent extends React.Component {
    
      onClick() {
        // fist child need have handleSubmit
        this.refs.child0.handleSubmit()
        this.toggleDialog()
      }
    
      render() {
    
        const children = React.Children.map(this.props.children,
          (child, index) => React.cloneElement(child, {
            ref : `child${index}`
          })
         );
    
        return (
            <div>
              <DialogContent>
                {children}
              </DialogContent>
            <button onClick={this.onClick}></button>
          </div>
        );
      }
    }
    
  3. index.js

    <Parent>
       <Child/ >
    </Parent>
    
Mithril
  • 12,947
  • 18
  • 102
  • 153
1

You can do simply like this: (the code was tested!)

Parent.js

class Parent extends React.Component {

  onClick() {
    // take notice to the array's index "children[0]" (you can also loop the children array)
    this.refs.wrapper.children[0].method();
  }

  render() {
    const {children} = this.props;
    // you must put the ref="wrapper" to locate the container element wrapping all the children
    return (
      <div ref="wrapper">
        {children}
        <button onClick={this.onClick.bind(this)}>click</button>
      </div>
    );
  }
}

Child.js (no change)

class Child extends React.Component {
  method() {
    alert(1111);
  }
  render() {

    return (
      <div>
        ....
      </div>
    );
  }
}

index.js: (no change)

<Parent>
   <Child/ >
</Parent>
thinhvo0108
  • 2,212
  • 1
  • 13
  • 23
  • And there is a drawback, you have to use a dom element instead of a react component to wrap `children` . Because react component's may be multi-level, children would be wrong. So I prefer @Panther 's solution. – Mithril Sep 13 '17 at 01:28
  • OK I see, if you have complicated children structure inside the parent DOM, or if you cannot put "ref" into that parent DOM, then my solution cannot help! But my solution works in other cases, not sure about your current DOM structure, or maybe you applied many other middleware or other react libraries. If I can see your real project's code, I may think of other better solution! – thinhvo0108 Sep 13 '17 at 06:51
1

Using refs is not recommended. You can use componentWillReceiveProps to handle the change in props from the parent or you could use shouldComponentUpdate to handle change in either props or state.

But, in shouldComponentUpdate you can easily control the render sequence of the child component.

backslashN
  • 2,795
  • 3
  • 15
  • 25