简体   繁体   中英

TypeError: Cannot read property 'isCompleted' of undefined - React simple todo app

I want to make a simple todo app with React. For some reason every try i try to toggle todo element isCompleted state i get an error:

TypeError: Cannot read property 'isCompleted' of undefined - React simple todo app

React debugger highlight line 37 and 41. I honestly can't find the reason why it doesn't work it seem like setState in toggleTodo breaks something.

import React, { Component } from 'react';

const Input = (props) => {
  return (
    <form onSubmit={props.addTodo}>
      <input placeholder="What needs to be done?" value={props.newTodo} className="new-todo" type="text" onChange={props.handleChange} />
      <input type="submit" value="Submit" />
    </form>
  );
}

const TodoListTable = props => {
  return (
    <ul className="todo-list">
      {props.todoList.map((item, index) => {
        return (
          <li key={index} id={index}>
            <button className="toggleTodo" onClick={props.toggleTodo}>
              {item.isCompleted ? "(X)" : "( )"}
            </button>
            <span className="textTodo">{item.text}</span>
            <button className="deleteTodo" onClick={props.removeTodo}>
              X
            </button>
          </li>
        );
      })}
    </ul>
  );
};
const FilterListTable = props => {
  return <ul className="filters">
      <li>
        <a href="#/">All</a>
      </li>
      <li>
        <a href="#/active">Active</a>
      </li>
      <li>
        <a href="#/completed">Completed</a>
      </li>
    </ul>;
};

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
    newTodo: "",
    todoList: [
      { text: "zrobić pranie", isCompleted: false },
      { text: "zrobić lunch", isCompleted: true },
      { text: "zrobić pranie", isCompleted: false }
    ]
   }
  }

  handleChange = event => {
    this.setState({ newTodo: event.target.value });
  };
  addTodo = event => {
    event.preventDefault();
    this.setState(prevState => ({
      newTodo: "",
      todoList: [...prevState.todoList, { text: this.state.newTodo }]
    }));
  };
  editTodo = event => {
    // event.preventDefault();
    // console.log(this.state.todoList);
  };
  toggleTodo = event => {
    event.preventDefault();
    let todoId = event.target.parentNode.id;
    console.log(todoId);
    this.setState(prevState => ({
       todoList: prevState.todoList.map((number, i) => {
       })
    }));
  };
  removeTodo = event => {
    event.preventDefault();
    let todoId = event.target.parentNode.id;
    console.log(todoId);
    this.setState(prevState => ({
      todoList: prevState.todoList.filter((number, i) => i != todoId)
    }));
  };
  render() {
    return (
      <div className="todoapp">
        <h1>React Todo</h1>
        <Input addTodo={this.addTodo} handleChange={this.handleChange} />
        <TodoListTable
          todoList={this.state.todoList}
          toggleTodo={this.toggleTodo}
          removeTodo={this.removeTodo}
        />
        <hr />
        <FilterListTable />
        <br />
      </div>
    );
  }
}

export default App;

In your toggleTodo function, also you need to return the updated todoList in the toggleTodo function which you aren't doing

Check the toggleTodo function

toggleTodo = event => {
    event.preventDefault();
    let todoId = event.target.parentNode.id;
    console.log(todoId, 'td');
    this.setState(prevState => ({
      todoList: prevState.todoList.map((todos, i) => {
        if(i == todoId) {
          todos.isCompleted = !todos.isCompleted
        }
        return todos
      })
    }));
  };

working sandbox

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM