Skip to content

Output data from form on the page react

I am writing todo app. There are main files in my directory now:

App (rendering main page with header and buttons)

 export default class App extends React.Component {
   constructor(props) {
   super(props);
   this.state = { triggerText: 'Create a task' };
}
propTypes = {
  triggerText: PropTypes.string.isRequired,
  handleSubmit: PropTypes.object.isRequired,
};

render() {
  const { triggerText } = this.state;
  const { handleSubmit } = this.props;
  return (
   <div className="App">
     <header className="App-header">
     <h1>To Do List</h1>
     <div id="tasksList">
      <span className="tasks active">Tasks</span>
    </div>
    <div id="categoriesList">
    <span className="categories">Categories</span>
    </div>
    <div>
    <Container triggerText={triggerText} onSubmit={handleSubmit} /> // creates modal dialog and uses TodoForm
    </div>
  </header>
  <div id="container" className="container">
      <TodoBox tasks={[]}/>
    </div>
   </div>
  );
 }
}

TodoForm (create a form)

export default class TodoForm extends React.Component {
  constructor(props) {
  super(props);
  this.state = { value: '', tasks: [] };
}
propTypes = {
handleSubmit: PropTypes.object.isRequired,
}

handleRemove = (currentTaskId) => (e) => {
  e.preventDefault();
  const { tasks } = this.state;
  this.setState({ tasks: tasks.filter(({ id }) => id !== currentTaskId) });
};

handleChange = (e) => {
  e.preventDefault();
  this.setState({ value: e.target.value });
}

handleSubmit = (e) => {
  e.preventDefault();
  const { value, tasks } = this.state;
  const newTask = { id: uniqueId(), text: value };
  this.setState({ value: '', tasks: [newTask, ...tasks] });
}

render() {
  const { value } = this.state;
  return (
    <form onSubmit={this.handleSubmit}>
      <div className="form-group">
        <label htmlFor="text"><strong>Create a task</strong></label>
        <input
        type="text"
        onChange={this.handleChange}
        value={value}
        required
        className="form-control"
        id="text"
        placeholder="I am going..."
      />
      </div>
      <div className="form-group">
        <button type="submit" className="form-control btn btn-primary">Add</button>
        </div>
    </form>
    );
  }
}

TodoBox (generating list of tasks)

class Item extends React.Component {
  propTypes = {
  onRemove: PropTypes.object.isRequired,
  task: PropTypes.string.isRequired,
};
 render() {
    const { task, onRemove } = this.props;
    return (
      <div className="row">
        <div>
          <button type="button" className="btn btn-primary" onClick={onRemove}>-</button>
        </div>
        <div className="col-10">{task.text}</div>
      </div>
    );
  }
}

  export default class TodoBox extends React.Component {
    constructor(props) {
      super(props);
  }
   propTypes = {
    tasks: PropTypes.string.isRequired,
  }
   render() {
    const { tasks } = this.props;
    return (
     <div className="item">
       {tasks.map((task) => (
       <div key={task.id}>
       <Item task={task} onRemove={this.handleRemove} />
       <hr />
     </div>
     ))}
   </div>
   );
 }
}

And the question is: how I can pass the state from TodoForm to TodoBox in App (it is initialize as an empty array now). I want to output tasks at the bottom of the same page in container after header element.

Answer

You can create a function (addTodo) in App component and pass it down to the TodoForm component. In TodoForm component you can invoke the addTodo function from props and send the todoValue as arguments props.addTodo(todoValue). In addTodo function in App component you can update the todoValue to state. Once you update the state it will re-render the App component, then the TodoBox component will call with the updated todoValue value.

Note: But it is not best practice. The best practice is to use React Context