Daniel Zuzevich Daniel Zuzevich - 1 year ago 63
Javascript Question

React Event Handler. Adding values to array

Why Hello Javascript Wizards,

I am really starting to dive into React and have to say, I find it very interesting. However, I am having an issue in regards to taking the value from an input form, and adding it into an array. I am building a small to do app(how creative of me), and I am attempting to add the value in the input field to an array each time the add button is clicked.

Here's the catch, it works just fine, just not on the first submit of the button. For example, lets say I boot up the app, type "Hello" into the input field, and hit enter. As you can see in my code, I have a console.log setup at the end of the function so I can see what is going on each time the button is clicked.

The first time the button is clicked, all I get logged to the console is "[]", on the next click, I then see what I wanted, where I get a log saying, ["Hello"]. Any other input I add after that gets added just swimmingly to the array. I feel as there has to be something quite minute going on that may just require a more seasoned pair of eyes. I would appreciate any feedback on a possible solution, and perhaps any ways I could make the code better.

Here is a quick screenshot of the console. The first click starts at the [] part.

enter image description here

import React, { Component } from 'react';
import ListItem from './list-item';

export default class App extends Component {
constructor(props) {

this.state = { tasks: [] };
this.addTask = this.addTask.bind(this);

addTask(event) {
var form = this._input.value;
var allTasks = this.state.tasks.concat([form]);
this.setState({tasks: allTasks});

render() {
return (
<div className="app-main">
<div className="col-sm-12 text-center">
{/* App Title */}
<h1>Task App</h1>
<div id="formWrapper">
{/* Start of Form */}
<form onSubmit={this.addTask}>
<input ref={(el) => this._input = el} />
<button type="submit" className="btn btn-md btn-primary">Add</button>
{/* List Item */}
<ListItem tasks={this.state.tasks} />

Answer Source

As per the docs,

setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.

There is no guarantee of synchronous operation of calls to setState and calls may be batched for performance gains.

From the notes section of setState, my emphasis in bold. So setState doesn't immediately mutate state. Although, when setState has merged the new state in, it will always call render again so ListItem will get the new task just not synchronously, or perhaps, not immediately.

Move your console.log down into your render function and you'll see the difference:

<ListItem tasks={this.state.tasks} />