Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React ES6 parent child components state issue

I am new to react and trying to build a simple ToDo app based off of the react-starter-kit. I am using ES6 classes and unable to find a way to update parent state from a child component.

Here is the code:

import React, { PropTypes, Component } from 'react';
import withStyles from '../../decorators/withStyles';
import styles from './ToDoPage.less';


@withStyles(styles)
class ToDoPage extends Component {

  static contextTypes = {
    onSetTitle: PropTypes.func.isRequired
  };

  constructor() {
    super();
    this.state = {
      items: ['Item1', 'Item2'],
      value: ''
    };
  }

  updateValue(newValue) {
    //this.state is null here
    this.setState({
      value: newValue 
    });
  }

  clickHandler() {
    console.log('AddToDo state:', this.state)
    if (this.state.value && this.state.items) { //this.state is null here
      this.setState({
        items: this.state.items.push(this.state.value)
      });
    }
  }

  render() {
    let title = 'To Do List';
    this.context.onSetTitle(title);
    return (
      <div className="ToDoPage">
       <div className="ToDoPage-container">
        <h1>{title}</h1>
          <AddToDoTextBox handleUpdate={this.updateValue}/>
          <AddToDoButton handleClick={this.clickHandler}/>
          <div className = "todo-items">
           <br/>
           <div>({this.state.items.length}) items found.</div>
           <ToDoList items = {this.state.items}/>
          </div>
        </div>
      </div>
    );
  };
}

class ToDoList extends Component {
  static propTypes = {
    items: PropTypes.array.isRequired
  };

  render() {
    console.log(this.props.items);
    return (
            <ul>
            {this.props.items.map(function(item) {
             return <li key={item}>{item}</li>
            }) }
            </ul>); 
  };
};

class AddToDoButton extends Component {
  static propTypes: {
    clickHandler: React.PropTypes.func 
  }

  constructor() {
    super(); 
  }

  render() { 
    return (<button 
            className="btn btn-primary" 
            onClick={this.props.handleClick.bind(this)}>Add ToDo</button>); 
  };
}

class AddToDoTextBox extends Component {
  static propTypes: {
    handleUpdate: React.PropTypes.func
  }

  constructor() {
    super();
    this.state = {
      value: '' 
    };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.setState({value: e.target.value}); 
    this.props.handleUpdate.call(this, e.target.value);
  }

  render() {
    return <input type="text" placeholder="Enter todo item here" size="50" onChange={this.handleChange}/> 
  };
}
export default ToDoPage;

I want to access ToDoPage's state from updateValue() and clickHandler() functions but this.state is null as I binding to the child components they are being called from (i.e AddToDoButton and AddToDoTextBox). How can I access/update ToDoPage's state from clickHandler() or updateValue()?

like image 855
Harish Avatar asked Jul 13 '15 15:07

Harish


People also ask

How to update parent and child components state in react JS?

Update Parent and Child Components State in React.js May 08, 2020 When you nest your components in react.js, in some cases, you may want to update the state of the parent component from the child component or vice versa. To achieve this sort of communication you can simply use props and references.

How to pass props from parent component to child component?

So, based on selectio, data on child component must change. The solution is to maintain state in parent component, and pass the props to child component. And the child component, will read data from props. Now the child component will just render data from its props. Hope it helps.

What is react context and how to use it?

— React Context provides a way to pass data through the component tree without having to pass props down manually at every level ☘️ In any application, data is essential. We all know this, in React, state and props are two very important properties and are commonly used, easily explained: they are all used to save the state of the data.

How to handle react state update and return the new state?

Let’s take a look at the the code snippet that handles React state update and returns the new state object to the parent component. In the handleChange () method, I’m calling this.setState (), and updating the component state object with the new values.


2 Answers

When you want to do change from Child to Parent you need to pass a function to the Child as prop. Something like (example with some ES7 syntax):

Parent component

import React, { Component } from 'react'

export default class Parent extends Component {
  constructor() {
    super();

    this.handleChange = this.handleChange.bind(this);
    this.state = {
      number: 1
    };
  }

  handleChange(num) {
    this.setState({
      number: num
    });
  }

  render() {
    return (
      <Child changeNumber={this.handleChange} />
    );
  }
}

Child component

import React, { PropTypes, Component } from 'react'

export default class Child extends Component {
  static propTypes = {
    changeNumber: PropTypes.func
  }

  constructor() {
    super();

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(e) {
    e.preventDefault();
    this.props.changeNumber(e.target.value);
  }

  render() {
    return (
      <button onClick={this.handleClick}> 3 </button>
    );
  }
}
like image 96
knowbody Avatar answered Oct 12 '22 07:10

knowbody


You need to use .bind(this) at your handleUpdate and handleClick assignments in ToDoPage.render():

      <AddToDoTextBox handleUpdate={this.updateValue.bind(this)}/>
      <AddToDoButton handleClick={this.clickHandler.bind(this)}/>

or use arrow functions

See https://facebook.github.io/react/docs/reusable-components.html#no-autobinding

like image 34
llernestal Avatar answered Oct 12 '22 06:10

llernestal