首页 > 解决方案 > 我认为渲染工作两次

问题描述

我只是在学习 React,试图编写一个简单的 TODO 列表应用程序。当我尝试添加新任务时,会添加两个相同的任务。我尝试通过 console.log 元素进行调试,发现了一个问题。渲染工作两次,所以我的按钮两次向函数发送信息。有人可以指导我解决问题吗?这是代码。

    import React from 'react';

    class TaskInput extends React.Component {
      constructor(props) {
        super(props);

        this.state = {
          input: ''
        };
      }

      addTask = () => {
        const { input } = this.state;
        if (input) {
          this.props.addTask(input);
          this.setState({ input: '' });
        }
      };

      handleEnter = event => {
        if (event.key === 'Enter') this.addTask();
      };

      inputChange = event => {
        this.setState({ input: event.target.value });

      };

      render() {
        const { input } = this.state;
        console.log(this.state); 
        return (
          <div className="task-input">
            <input
              type="text"
              onKeyPress={this.handleEnter}
              onChange={this.inputChange}
              value={input}
            ></input>
            <button onClick={this.addTask } >ADD</button>

          </div>
        );
      }
    }

    export default TaskInput;

这是 App.js 代码:

    import React from 'react';
    import Task from './components/Task';
    import TaskInput from './components/TaskInput';

    class App extends React.Component {
      constructor () {
        super();

        this.state = {
          tasks: [
            {id: 0, title: 'Create Todo-app', done: false},
            {id: 1, title: 'Do smth else', done: true},
            {id: 2, title: 'Do more things', done: false}
          ]
        };
      }

    addTask = task => {
      this.setState(state => {
        let {tasks} = state;
        console.log("state");
        tasks.push({
          id: tasks.length !==0 ? tasks.length : 0,
          title: task,
          done: false
        });
        return tasks;
      });
    }

    doneTask = id => {
      const index = this.state.tasks.map(task => task.id).indexOf(id);
      this.setState(state => {
        let {tasks} = state;
        tasks[index].done = true;
        return tasks;
      });
    };
    deleteTask = id => {
      const index = this.state.tasks.map(task => task.id).indexOf(id);
      this.setState(state => {
        let {tasks} = state;
        delete tasks[index];
        return tasks;
      })
    };
    render() {

      const { tasks } = this.state;
      const activeTasks = tasks.filter(task => !task.done);
      const doneTasks = tasks.filter(task => task.done)

       return (
       <div className = "App">
         <h1 className="top">Active tasks: {activeTasks.length}</h1>
         {[...activeTasks, ...doneTasks].map(task => (
          <Task
            doneTask={() => this.doneTask(task.id)}
            deleteTask={() => this.deleteTask(task.id)}
            task={task}
            key={task.id}
             ></Task>))}
             <TaskInput addTask={this.addTask}></TaskInput>
       </div>
       );
      }
    }
    export default App;

标签: reactjsrender

解决方案


我认为您不小心直接修改了里面的状态addTask

该行let {tasks} = state;正在创建对原始状态的引用,而不是新副本,然后您的推送直接修改状态。

使用扩展/扩展语法来获取数组的副本应该可以:

addTask = task => {
  this.setState(state => {
    const tasks = [ ...state.tasks ];
    tasks.push({
      id: tasks.length !==0 ? tasks.length : 0,
      title: task,
      done: false
    });
    return { tasks };
  });
}

usinglet tasks = [ ...state.tasks ];将创建一个新数组而不是引用,并防止直接修改状态。

您看到双重结果的原因是您通过推送有效地设置了状态,然后使用返回值再次设置它。


推荐阅读