2

I have simple component called List which is a simple ul with some li inside. Each li is a simple component. I have other parent component which render one input field and the List component. Tapping on Send key I catch text of input field. I want to call for example a function called handleNewText(inputText) but this function need to stay inside List component because the state I use to populate other li components live in List component.

I don' t want to refactor List and MyParent component passing the manage of data from List to MyParent.

first is parent and second is child

class TodoComp extends React.Component {
  constructor(props){
    super(props);
    this.handleKeyPress = this.handleKeyPress.bind(this);
  }

  componentDidMpunt(){
    console.log(this._child.someMethod());
  }


  handleKeyPress(event){
    if(event.key === 'Enter'){
      var t = event.target.value;

    }
  }

  render(){
    return (
        <div>
          <input
            className="inputTodo"
            type="text"
            placeholder="want to be an hero...!"
            onKeyPress={this.handleKeyPress}
          />
          <List/>
        </div>
    );
  }

}


export default class List extends React.Component {
  constructor() {
    super();
    this.flipDone = this.flipDone.bind(this);
    this.state = {
      todos: Array(3).fill({ content: '', done: false})
    };
  }

  flipDone(id) {
    let index = Number(id);

    this.setState({
      todos: [
        ...this.state.todos.slice(0, index),
        Object.assign({}, this.state.todos[index], {done: !this.state.todos[index].done}),
        ...this.state.todos.slice(index + 1)
      ]
    });
  }

  render() {

    const myList = this.state.todos.map((todo, index) => {
      return (
        <Todo key={index}
              clickHandler={this.flipDone}
              id={index}
              todo={todo}
              handleText={this.handleText}
        />
      );
    })

    return (
      <ul className="list">
        {myList}
      </ul>
    );
  }


ReactDOM.render(<TodoComp />,document.getElementById('myList'));
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
user3528466
  • 186
  • 2
  • 17

3 Answers3

6

You need to make use of refs to call a function in the child component from the parent component

render the List component from parent as

<List ref="myList"/>

and then access the handleNewText() function as this.refs.myList.handleNewText()

UPDATE:

Strings refs are no longer recommended by React, you should rather use ref callbacks, check this

<List ref={(ref) => this.myList=ref}/>

and then access the child function like

this.myList.handleNewText()
Shubham Khatri
  • 270,417
  • 55
  • 406
  • 400
1

Adding to @shubham-khatri solution:

If you are referencing a connected child component...

a. That child must say withRef: true in the (4th) config parameter:

@connect(store => ({
    foo: store.whatever
    …
}),null,null,{ withRef: true })

b. Access is through getWrappedInstance() (note, that getWrappedInstance also needs to be called ())

getWrappedInstance().howdyPartner()
Frank N
  • 9,625
  • 4
  • 80
  • 110
0

I started learning React when functional component came out. Another way I experimented with some success is returning functions that you want to access as closures within a JSON. I like this method because closure is a construct of Javascript and it should still work even if React is updated yet again. Below is an example of child component

function Child(){
    //declare your states and use effects
    const [ppp, setPPP] = useState([]);
    const [qqq, setQQQ] = useState(2);
    //declare function that you want to access
    function funcA(){ /*function to interact with your child components*/}
    function funcB(){ /*function to interact with your child components*/}

    //pure React functional components here
    function Content(){
         //function that you cannot access
         funcC(){ /*.....*/}
         funcD(){/*.......*/}
         //what to render
         return (
           <div> 
               {/* your contents here */} 
           </div>
         )
    }
    //return accessible contents and functions in a JSON
    return {
        content: Content, //function for rendering content
        ExposeA: funcA,   //return as a closure
        ExposeB: funcB,   //return as a closure
    }
}

Below is an example of how you would render the child contents within the parent

function Parent(){
    let chi = Child();
    let ChildContent = chi.Content;
    //calling your exposed functions
    //these function can interacts with the states that affects child components
    chi.ExposeA();  
    chi.ExposeB();
    //render your child component
    return (<div>
        <div> {/* parent stuff here */</div>
        <div> {/* parent stuff here */</div>
        <ChildContent {/*Define your props here */} />
    </div>)
}