Usman
Usman

Reputation: 165

How to add to state array in React

I am making a simple to-do list app in React. I have 3 states, inputText (the task the user enters), triggerAnimation(to trigger animations), and tasks (the list of tasks user has entered). However I don't know how to update the tasks state (which is an array) to push the new tasks. Here is the code.

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      inputText: '',
      triggerAnimation: '',
      tasks: []
    }
  }

//The function triggered by button which sends the task the user has entered to the tasks array state:

  addItem() {
    document.querySelector("#textfield1").value = ""
    this.setState({ 
      triggerAnimation: 'fadein', tasks: 
      this.state.inputText 
    }) 
  }



  render() {
    //Where User enters task:
    return (
      <div className="App">
        <main>
          <div className="enterTask">
            <input type="text" className="inputclass" id="textfield1" 
              placeholder='Enter a task.' 
              onChange={event => this.setState({ 
                inputText: event.target.value })} 
              onKeyPress={event => {
                if(event.key === 'Enter') {
                  this.addItem();
                }
               }} 
             />
            <br />
            <br />
            <button className="button" 
              onClick={() => this.addItem()} data-
                toggle='fadein' data-target='list'>+
            </button>
         </div>


    <!-- Where tasks will appear: -->

         <div className="log">
           <p className='list'>
             <span class={this.state.triggerAnimation}>  
               {this.state.tasks}
             </span>
           </p>
           <button className="button">-</button>
         </div>
       </main>
     </div>
    )
  }
}  

export default App;

Upvotes: 7

Views: 15902

Answers (6)

shaunhusain
shaunhusain

Reputation: 19748

FTFY better to just use comments in the code, regarding the problem(s) you want to get the tasks array then can concat the stuff to get a new array.

setState({tasks:this.state.tasks.concat([this.state.inputText])})

Wouldn't hurt to clean up the code some too... learning react myself the book "the road to learning react" has some good tips on how to set things up to be a bit more readable.


Edit actually put the right code here now...

Upvotes: 1

Alex Fallenstedt
Alex Fallenstedt

Reputation: 2093

You can use .concat method to create copy of your array with new data:

  addTask() {
    this.setState({tasks: this.state.tasks.concat(["new value"])})
  }

You also need to bind this to addTask in your constructor:

this.addTask = this.addTask.bind(this)

See my example:

https://jsfiddle.net/69z2wepo/103069/

Documentation: https://reactjs.org/docs/react-component.html#setstate

Upvotes: 3

Aaron Beall
Aaron Beall

Reputation: 52133

However I don't know how to update the tasks state (which is an array) to push the new tasks.

Probably the cleanest way to "push to an array" in state is to use ES6 array spread. The best practice would also be to use the setState callback syntax to ensure the correct state is committed before you push the new task:

this.setState(prevState => ({
  tasks: [...prevState.tasks, newTask] 
}));

Upvotes: 9

Shanon Jackson
Shanon Jackson

Reputation: 6531

Seems like what you want is this..

addItem() {
document.querySelector("#textfield1").value = ""
this.setState({
            triggerAnimation: 'fadein',
            tasks: this.state.tasks.concat(this.state.inputText)}) 
}

Upvotes: 4

Fadi Quader
Fadi Quader

Reputation: 153

try this

import React from 'react';

class Todo extends React.Component {
  constructor(props) {
    super();
    this.state = {
      value: '',
      items: []
    }
  }

  onChange = e => this.setState({ value: e.target.value })

  onEnter = e => {
    if(e.charCode !== 13) return;
    this.addItem();
  };

  onClick = e => {
    this.addItem()
  };

  addItem = () => {
    const { value } = this.state;
    if(!!value.trim()) return;
    this.setState(prev => ({ items: [...prev.items, value], value: '' }))
  };

  render() {
    const { value } = this.state
    return (
      <div>
        <div>
          <input
            type="text"
            value={value}
            name="abc"
            onChange={this.onChange}
            onKeyPress={this.onEnter}
          />
        </div>
        <button onClick={this.onClick}>Add</button>
      </div>
    )
  }
}

Upvotes: 1

Varinder
Varinder

Reputation: 2664

With react, you're almost always going to have to store form field information in state (controlled components) so, how about turning todo task input field into a controlled component, like so:

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

class App extends Component {
    constructor(props) {
        super(props);

        this.state = {
            inputText: '',
            triggerAnimation: '',
            tasks: []
        }

        this.onInputChange = this.onInputChange.bind(this);
        this.onInputKeyPress = this.onInputKeyPress.bind(this);
        this.addItem = this.addItem.bind(this);
    }

    onInputChange(e) {
        this.setState({ inputText: e.target.value });
    }

    onInputKeyPress(e) {
        if (e.key === "Enter") {
            this.addItem();
        }
    }

    addItem() {
        const itemToAdd = this.state.inputText;
        const tasks = this.state.tasks;
        this.setState({
            inputText: "",
            tasks: tasks.concat(itemToAdd);
        });
    }

    render() {
        const { inputText } = this.state;
        return(
            <div>
                <input type="text" className="inputclass" id="textfield1" placeholder='Enter a task.' 
                   value={inputText} onChange={this.onInputChange} onKeyPress={this.onInputKeyPress} />
                <br />
                <br />
                <button className="button" onClick={this.addItem} data-
                toggle='fadein' data-target='list'>+</button>
            </div>
        );
    }
}

Notice how input state is controlled via component state

Upvotes: 0

Related Questions