Mapping array to make list

So I was trying to make a list based off the input from a textbox, but my text input no longer shows up, and I get a object error in code pen. Here is what I have. Anything you see wrong would be helpful. Just went through the react part the other day, so im pretty new to it

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      newTodo: '',
      todo: []
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(event) {
    this.setState({
      newToDo: event.target.value
    });
  }
  handleSubmit(event) {
    
    event.preventDefault();
const newArr = [this.state.todo, this.state.newToDo]
this.setState({newArr, newToDo: ''});
  }
  render() {
    const items = newArr.map((items) => <li>{items}</li>)
    return (
      <div>
<form onSubmit={this.handleSubmit}>
          
    <input
    value = {input}
    onChange = {this.handleChange}
    />
    <button type='submit'>Submit!</button>
 </form>
       
  <ol>{items}</ol>

       
      </div>
    );
  }
};

ReactDOM.render(<MyForm />, document.getElementById('app'));

In your Myform component’s render method, you reference a newArr variable, but there is no newArr in the same method or in the global scope. You do have a newArr variable in your handleSubmit method, but it is not accessible by the render method.

Also, your render method references an input variable (see in the following line of code), but there is no input variable anywhere in your code, so it errors out because input is not defined.

<input value={input} onChange={this.handleChange} />

I saw that a few minutes ago actually. Trying to many different things that I was not careful to change or get rid of everything. Here is what I have now

class MyForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      newTodo: '',
      todo: []
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }
  handleChange(event) {
    this.setState({
      newTodo: event.target.value
    });
  }
  handleSubmit(event) {
    
    event.preventDefault();
const newArr = [...this.state.todo, this.state.newToDo];
this.setState({newArr, newToDo: ''});
  }
  render() {
    const items = this.state.todo.map((items) => <li>{items}</li>)
    return (
      <div>
<form onSubmit={this.handleSubmit}>
          
    <input
    value = {this.state.newTodo}
    onChange = {this.handleChange}
    />
    <button type='submit'>Submit!</button>
 </form>
       
  <ol>{items}</ol>

       
      </div>
    );
  }
};

ReactDOM.render(<MyForm />, document.getElementById('app'));

Some of this code was from a udemy lesson, but he initializes several ‘todos’, so its hard to see which one he is talking about.

in the udemy code he adds the empty array of todos and the newtodo to the new array.

 const todos = [...this.state.todos, this.state.newTodo];
 this.setState({todos, newTodo: ''});

I dont see why he adds the empty array here? Or what newArr is being set to in the setState?
The new newtodo there just clears the input field.

Here is the code I am talking about, and trying to follow along/understand

You should learn how to properly indent your code to make it easier for someone else to read. I have formatted your handleSumbit function below.

  handleSubmit(event) {
    event.preventDefault();
    const newArr = [...this.state.todo, this.state.newToDo];
    this.setState({ newArr, newToDo: "" });
  }

You have a newArr variable here which is a new array containing all of the existing todo array elements along with the newly added newToDo value. This is fine, but now you need to update the your component’s state, so the state’s todo value gets updated to newArr. You wrote:

this.setState({ newArr, newToDo: "" });

The above line adds a property named newArr which contains the array referenced in newArr. That is not what you want. Instead, you want to update the property named todo with newArr.

this.setState({todo: newArr, newToDo: ""});

If you would have just named the new array todo instead, you could have written:

const todo = [...this.state.todo, this.state.newToDo];
this.setState({ todo, newToDo: "" });

But wait, even if you resolve this issue, you will still not see any items added to a to do list on the page. Why? Well, you have some typos/inconsistencies in naming your input element’s value. In some parts of the code you write newToDo and other parts you write newTodo. JavaScript is case-sensitive, so you need to pick one spelling and stick with it. I will let you work out that detail.

I will work on that. The one thing I’m still confused it. The original array is empty. There are no to dos in it. So what’s the point on adding the todo array to the newArr? In the GitHub code I posted, and tried to follow I don’t see where todo gets any values.

todo needs to be an array, because you need a data structure to add and display the list items. It needs to be an empty array, because if not, how would you add new elements (to do items) to it during the handleSubmit method?

Let’s say you set the original value of the todo property to a blank string in the constructor method. You would have to add a lot of extra logic to check first if todo is already an array or if it is not an array. If it is not, then you need to create a new array and add the newTodo item to it. By having todo start as an array, you simplify the code inside handleSubmit.

FYI - You could update todo using concat instead of using the spread operator.

const todo = this.state.todo.concat(this.state.newTodo);

In the github code, there is no todo property in this.state. Instead, the author uses a todos property which actually reads better. Basically, where ever you reference todo, the author references todos.

1 Like

Makes more sense. Never knew

this.setState({ todo, newToDo: "" });

meant todo:todo. Thats where a lot of confusion came from, it was not explained in his video or before that video.