Table 值在反应中没有改变

Table values does not change in react

我正在从 API 获取数据并从前端更改值以在 table 中显示它。我正在获取 object 的列表并将其存储在一个状态中,并在 html table 中显示该状态中的 object。 table 有一个显示布尔值的复选框。如果该值为 true,则复选框中的 defaultChecked 为 true。 table header 中有一个复选框,用于选中或取消选中所有项目。

下面是我取的jsonobject

{
completed: false
id: 1
title: "delectus aut autem"
userId: 1
}

如果我勾选了 table header 中的复选框,我想在所有 200 个项目中将 completed 设置为 true

以下是将所有项目设置为 true 或 false 的代码。

const checkAllHandler = (e) => {
    let val = e.target.checked;
    console.log(val);
    let allTodoList = [];

    if (val === true) {
      if (todo.length > 0) {
        
        for (let index = 0; index < todo.length; index++) {
          const newObject = {
            userId: todo[index].userId,
            id: todo[index].id,
            title: todo[index].title,
            completed: true,
          };
          allTodoList.push(newObject);
        }
        setTodo(allTodoList);
        
      }
    } else if (val === false) {
      if (todo.length > 0) {
       
        for (let index = 0; index < todo.length; index++) {
          const newObject = {
            userId: todo[index].userId,
            id: todo[index].id,
            title: todo[index].title,
            completed: false,
          };
          allTodoList.push(newObject);
        }
        setTodo(allTodoList);
        
      }
    }
  };

当我控制 todo 状态时,所有值都更新为 true 或 false,但它没有显示在 table 上。 table 具有过滤功能。如果我过滤一个词然后返回,那么整个 table 的值都在改变。我想在单击复选框时显示更改,而不是在搜索和返回时显示更改。我该怎么做?

该组件的完整代码如下。

const DataTable = () => {
  const { loading, items } = useSelector((state) => state.allData);
  // console.log(items)

  const dispatch = useDispatch();
  // const history = useNavigate();

  const [searchText, setsearchText] = useState("");
  const [todo, setTodo] = useState(items);
  console.log("todo");
  console.log(todo);
  const [isFetch, setisFetch] = useState(false);
  const [checkedloading, setcheckedLoading] = useState(false);
  const [isChecked, setisChecked] = useState(false);
  console.log(isChecked);

  useEffect(() => {
    const setDataToState = () => {
      if (loading === false) {
        setTodo(items);
      }
    };
    setDataToState();
  }, [loading]);

  useEffect(() => {
    
    dispatch(getData());
    // setTodo(items)
    // console.log(items)
  }, [dispatch]);
  //etTodo(items)
  const handleSearch = (event) => {
    //let value = event.target.value.toLowerCase();
    setsearchText(event.target.value);
  };

  const onChangeHandler = (e, item) => {
    console.log(e.target.checked);
    console.log(item);

    if (e.target.checked === true) {
      // const item = todo.filter(x=> x.id === id)
      // console.log("added")
      // console.log(item)

      for (let index = 0; index < todo.length; index++) {
        if (todo[index].id === item.id) {
          console.log(todo[index]);
          console.log("deleting");
          todo.splice(index, 1);
          console.log("deleted");
          const newObject = {
            userId: item.userId,
            id: item.id,
            title: item.title,
            completed: true,
          };
          console.log("adding updated object");
          todo.splice(index, 0, newObject);
          console.log("added");

          console.log(todo);
        }
      }
    } else {
      // const item = todo.filter(x=> x.id === id)
      // console.log("removed")
      // console.log(item)
      for (let index = 0; index < todo.length; index++) {
        if (todo[index].id === item.id) {
          console.log(todo[index]);
          console.log("deleting");
          todo.splice(index, 1);
          console.log("deleted");
          const newObject = {
            userId: item.userId,
            id: item.id,
            title: item.title,
            completed: false,
          };
          console.log("adding updated object");
          todo.splice(index, 0, newObject);
          console.log("added");

          console.log(todo);
        }
      }
    }
  };

  const onSubmitHandler = () => {
    localStorage.setItem("items", JSON.stringify(todo));
  };
  const getItem = () => {
    const items = localStorage.getItem("items");
    console.log("local storage items");
    console.log(JSON.parse(items));
  };

  const checkAllHandler = async (e) => {
    const { checked } = e.target;
    console.log(checked);
    setTodo((todos) =>
      todos.map((todo) => ({
        ...todo,
        completed: checked,
      }))
    );
   
  };

  return (
    <>
      {console.log("todo in render")}
      {console.log(todo)}
      <div className={styles.container}>
        <div className={styles.top}>
          <div className={styles.search_bar}>
            <input
              type="text"
              onChange={(e) => handleSearch(e)}
              placeholder="search by name"
            />
          </div>
        </div>

        <div className={styles.btn_container}>
          <button onClick={onSubmitHandler}>Submit</button>
        </div>

        <div className={styles.data_table_container}>
          {checkedloading === false ? (
            <>
              <div className={styles.data_table}>
                {loading || todo === null || todo === undefined ? (
                  <>
                    <p>Loading!!</p>
                  </>
                ) : (
                  <>
                    <table>
                      <tr>
                        <th>ID</th>
                        <th>userId</th>
                        <th>Title</th>
                        <th>
                          <>
                            Completed
                            <input type="checkbox" onChange={checkAllHandler} />
                          </>
                        </th>
                      </tr>
                      <tbody>
                        {todo
                          .filter((val) => {
                            if (searchText === "") {
                              return val;
                            } else if (
                              val.title.toLowerCase().includes(searchText)
                            ) {
                              return val;
                            }
                          })
                          .map((item) => (
                            <>
                              <tr key={item.id}>
                                <td>{item.id}</td>
                                <td>{item.userId}</td>
                                <td>{item.title}</td>
                                <td>
                                  <input
                                    type="checkbox"
                                    defaultChecked={item.completed}
                                    onClick={(e) => onChangeHandler(e, item)}
                                  />
                               
                                </td>
                               
                              </tr>
                            </>
                          ))}
                      </tbody>
                    </table>
                  </>
                )}
              </div>
            </>
          ) : (
            <>Loading</>
          )}
        </div>
      </div>
    </>
  );
};

代码沙盒link:https://codesandbox.io/s/flamboyant-proskuriakova-60t19

我在这段代码中没有发现任何明显的问题,但它非常冗长。除了分配的 completed 布尔值外,两个逻辑分支都是相同的。在 React 中更新数组时,通常使用 functional state updates 来制作 先前状态 的浅表副本,而不是回调范围内可能关闭的任何状态。

示例:

const checkAllHandler = (e) => {
  const { checked } = e.target;
  console.log(checked);
  setTodo(todos => todos.map(todo => ({
    ...todo,
    completed: checked,
  })));
};

如果从这里更新 table 还有进一步的问题,那么请添加其余的组件代码和您认为相关的任何其他代码。

更新

none 复选框输入在 table 中发生变化的原因是因为您使用了 defaultChecked 属性,这使得这些输入完全 不受控制 输入。它们在安装时采用初始 item.completed 值,除非您与复选框交互,否则不会从那里更改。

如果你想让他们从changes/updates响应到todo状态,那么他们应该被转换成完全controlled 输入并使用 checked 属性。

<input
  type="checkbox"
  checked={item.completed}
  onClick={(e) => onChangeHandler(e, item)}
/>

更新#2

onChangeHandler 中的 Array.prototype.splice 改变了单个复选框输入。 .splice 进行就地突变。同样,应该使用功能状态更新来浅拷贝先前的状态并通过 id.

检查匹配的 todo 对象
const onChangeHandler = (e, item) => {
  const { checked } = e.target;

  setTodo((todos) =>
    todos.map((todo) =>
      todo.id === item.id
        ? {
            ...todo,
            completed: checked
          }
        : todo
    )
  );
};