Я думаю, что рендер работает дважды - PullRequest
0 голосов
/ 25 марта 2020

Я только изучаю 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;

Вот приложение. 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;

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Я немного изменил ваш код. Это работает здесь. Не могли бы вы проверить?

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

    this.state = {
      input: "",
      tasks: []
    };
  }

  addTask = newTask => {
    this.setState(state => ({
      ...state,
      input: "",
      tasks: [...state.tasks, newTask]
    }));
  };

  handleEnter = event => {
    if (event.key === "Enter") this.addTask(event.target.value);
  };

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

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

ReactDOM.render(<TaskInput/>, document.querySelector("#root"));
.as-console-wrapper {
  max-height: 5px;
  }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>



<div id="root"></div>
0 голосов
/ 25 марта 2020

Я думаю, что вы случайно изменяете состояние внутри addTask.

Строка let {tasks} = state; создает ссылку на исходное состояние, а не на новую копию, а затем ваш pu sh изменяет состояние напрямую.

Использование синтаксиса расширения / распространения для получения копии вашего массива, как это должно работать:

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

Использование let tasks = [ ...state.tasks ]; создаст новый массив, а не ссылка, и предотвращают непосредственное изменение состояния.

Причиной появления двойных результатов было то, что вы фактически установили состояние с помощью pu sh, а затем снова задали его с помощью возвращаемое значение.

...