0

I'm sorry if this is a frequent question but it's something I'm reallly struggling to understand.

I'm building a basic to-do list app in React.

The container currently contains a form that takes in the information, and adds each item inputted an items array in the state. I then have a 'TaskList' component that takes this state and renders my tasks.

What I want to do is create a separate form component, instead of having the form within my container.

The issue is that if I just copy the code for the form into a new component, the state it will modify is its own, and therefore won't be accessible via the TaskList component to render the list of tasks.

Is there any way to have a component that can update the state of its parent component. My source code is below for reference.

export default class Container extends React.Component {
  constructor() {
    super();
    this.handleSubmit = this.handleSubmit.bind(this);
    this.state = {
      items: []
    }
  }

  handleSubmit(e) {
    e.preventDefault();
    var itemsArray = this.state.items;
    itemsArray.push(e.target.elements.task.value);
    this.setState({
      items: itemsArray
    })
    e.target.reset();
  }

  render() {
    return (
      <div className="">
        <header className="header">TODO</header>
          <form onSubmit={this.handleSubmit}>
            <input name="task" placeholder="Task"></input>
            <button type="submit">Add</button>
          </form>
          <TaskList data={this.state.items} />
      </div>
    );
  }
}
<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>

const TaskList = props => {
  var tasks = (props.data).map( (item, key) => { return <Task data={item} key={key} /> })

  return(
    <ul className="gif-list">
      {tasks}
    </ul>
  );
}

export default TaskList;
<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>
tomhughes
  • 4,597
  • 2
  • 24
  • 33
  • https://facebook.github.io/react/docs/lifting-state-up.html – Murat Karagöz May 18 '17 at 15:00
  • Best way to do this is to use a global state, like Redux. The official example is a Todo List : http://redux.js.org/docs/basics/ExampleTodoList.html – Victor Baron May 18 '17 at 15:07
  • Does this answer your question? [How to update parent's state in React?](https://stackoverflow.com/questions/35537229/how-to-update-parents-state-in-react) – tomhughes Jan 22 '20 at 19:16

1 Answers1

2

You can do it this way. Pass the parent function that change the state as a props to the form component. In the form handle submit function, call the parent function as this.props.addTodo(todoText).

Container.js

import React, { Component } from 'react';
import TaskList from './TaskList';
import Form from './Form';

export default class Container extends Component {
  constructor() {
    super();
    this.handleAdd = this.handleAdd.bind(this);
    this.state = {
      items: []
    }
  }

  handleAdd(todoText) {
    var itemsArray = this.state.items;
    itemsArray.push(todoText);
    this.setState({
      items: itemsArray
    })
  }

  render() {
    return (
      <div className="">
        <header className="header">TODO</header>
          <Form addTodo={this.handleAdd}/>
          <TaskList data={this.state.items} />
      </div>
    );
  }
}

Form.js

import React, { Component } from 'react';

export default class Form extends Component {
  handleSubmit(e) {
    e.preventDefault();
    let todoText = e.target.elements.task.value;
    if(todoText.length > 0) {
      e.target.elements.task.value = '';
      this.props.addTodo(todoText);
    }else{
      e.target.elements.task.focus();
    }
  }

  render() {
    return(
      <div>
        <form onSubmit={(e) => this.handleSubmit(e)}>
          <input name="task" placeholder="Task"></input>
          <button type="submit">Add</button>
        </form>
      </div>
    );
  }
}

TaskList.js

import React from 'react';

const TaskList = props => {
  var tasks = (props.data).map( (item, key) => { return <li key={key}>{item}</li> })

  return(
    <ul className="gif-list">
      {tasks}
    </ul>
  );
}

export default TaskList;
hmachahary
  • 474
  • 4
  • 12