反应待办事项清单:标记表单正在更新错误的待办事项(useState范围的问题)

时间:2020-06-02 14:44:27

标签: reactjs react-hooks use-state

建立一个反应任务列表,我有一个非常具体的错误,需要一些帮助。我添加了向每个待办事项添加标签的功能。它在列表中的最后一个待办事项上效果很好,但是如果我尝试在列表中更高级别的任何待办事项中输入内容,它将更新最后一个待办事项的输入字段中的值。这是沙盒链接,因此您可以了解我在说什么:https://codesandbox.io/s/trusting-architecture-xjkbf?file=/src/App.js

我的代码如下。我知道,问题在于在我调用setTag的范围之外声明了[tag,setTag] = useState。我只是不知道我需要在哪里放置它以便工作。 (我复制了所有代码,但可以肯定地确定该问题是Task组件的本地问题)

import React, { useState } from "react";
import "./styles.css";
import todoBlack from "./icons/todoBlack.png";

function TodoForm(props) {
  [val, setVal] = useState("");

  const handleSubmit = e => {
    e.preventDefault();
    if (val) {
      props.addTask(val);
      setVal("");
    }
  };

  return (
    <div className="row">
      <div className="col-2" />
      <div className="col-8">
        <form className="py-1" onSubmit={handleSubmit}>
          <input
            placeholder="New Item"
            className="w-100 p-2 border"
            type="text"
            value={val}
            onChange={e => setVal(e.target.value)}
          />
        </form>
      </div>
    </div>
  );
}

function Task(props) {
  [tag, setTag] = useState("");

  const handleSubmit = e => {
    e.preventDefault();
    if (tag) {
      props.addTag(props.index, tag);
      setTag("");
    }
  };

  return (
    <div
      className={props.task.isComplete ? "complete-task" : "incomplete-task"}
    >
      <li className="row w-100 py-2 mx-0 px-0 border-bottom">
        <div className="text-left col-2 todo-button">
          <button onClick={() => props.completeTask(props.index)}>
            <img src={todoBlack} height="25" alt="todo" />
          </button>
        </div>
        <div className="text-left col-4 my-auto">
          <p className="my-1">{props.task.text}</p>
        </div>
        <div className="text-left col-4 my-auto">
          <div>
            {props.task.tags
              ? props.task.tags.map((tag, index) => (
                  <p
                    className="mx-1"
                    key={index}
                    index={index}
                    style={{ display: "inline" }}
                  >
                    {tag}
                    <button onClick={() => props.removeTag(props.index, index)}>
                      x
                    </button>
                  </p>
                ))
              : ""}
          </div>
          <form onSubmit={handleSubmit}>
            <input
              className="w-50"
              placeholder="Add Tag"
              type="text"
              value={tag}
              onChange={e => setTag(e.target.value)}
            />
          </form>
        </div>
        <div className="text-right col-2">
          <button type="button" onClick={() => props.removeTask(props.index)} />
        </div>
      </li>
    </div>
  );
}

export default function App() {
  [tasks, setTasks] = useState([]);
  [globalTags, setglobalTags] = useState([]);

  const addTask = text => {
    const newTasks = [...tasks, { text }];
    setTasks(newTasks);
  };

  const removeTask = index => {
    const newTasks = [...tasks];
    newTasks.splice(index, 1);
    setTasks(newTasks);
  };

  const completeTask = index => {
    const newTasks = [...tasks];
    if (!newTasks[index].isComplete) {
      newTasks[index].isComplete = true;
    } else {
      newTasks[index].isComplete = false;
    }
    setTasks(newTasks);
  };

  const addTag = (index, text) => {
    const newTasks = [...tasks];
    if (newTasks[index].tags) {
      newTasks[index].tags.push(text);
    } else {
      newTasks[index].tags = [];
      newTasks[index].tags.push(text);
    }
    setTasks(newTasks);
  };

  const removeTag = (index, tagIndex) => {
    const newTasks = [...tasks];
    newTasks[index].tags.splice(tagIndex, 1);
    setTasks(newTasks);
  };

  const taskList = tasks.map((task, index) => (
    <Task
      key={index}
      index={index}
      task={task}
      completeTask={completeTask}
      isComplete={task.isComplete}
      removeTask={removeTask}
      addTag={addTag}
      removeTag={removeTag}
    />
  ));

  return (
    <div className="App">
      <TodoForm addTask={addTask} />
      <ul className="container-fluid">{taskList}</ul>
    </div>
  );
}

1 个答案:

答案 0 :(得分:1)

这是在示例中添加引用的方式。功能组件中没有this的概念。您需要使用useRefthis悬挂在函数外部,因此始终将其应用于最后一个函数,这就是为什么它适用于最后一个函数而不适用于其他函数的原因

https://codesandbox.io/s/strange-kowalevski-qyj4s