表值在反应中没有变化

Posted

技术标签:

【中文标题】表值在反应中没有变化【英文标题】:Table values does not change in react 【发布时间】:2022-01-24 04:21:06 【问题描述】:

我从 API 获取数据并从前端更改值以将其显示在表格中。我获取对象列表并将其存储在一个状态中并在 html 表中显示该状态下的对象。该表有一个复选框来显示一个布尔值。如果该值为 true,则复选框中的 defaultChecked 为 true。表格标题中有一个复选框可以选中或取消选中所有项目。

以下是我获取的json对象。


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

如果我选中表头中的复选框,我想在所有 200 个项目中将 completed 设置为 true

以下是设置所有项目为真或假的代码。

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 状态时,所有值都会更新为真或假,但它不会显示在表格上。 该表具有过滤功能。如果我过滤一个单词并返回,那么整个表的值都会发生变化。我想在单击复选框时显示更改,而不是在搜索和返回时显示更改。我该怎么做?

组件的完整代码如下。

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>
    </>
  );
;

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

【问题讨论】:

代码似乎没问题。该问题可能导致其他地方。代码也有点冗长。您可以使用 map 重构代码,例如 setTodo(todo.map(e=>(...e, completed: val))) 【参考方案1】:

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

例子:

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

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

更新

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

如果您希望它们响应todo 状态的更改/更新,则应将它们转换为完全受控 输入并使用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
    )
  );
;

【讨论】:

值正在更新。问题是它没有呈现更新的状态。如果我在搜索文本字段中输入内容,则只会显示更新。 用完整的源代码和代码框链接编辑了问题。 @Minsaf 好的,发现您使用的是非受控输入和受控输入,这就是它们没有更新的原因。为我的答案添加了更新。 @Minsaf 是的,你正在通过数组拼接改变todos 状态。再次检查代码框。功能状态更新再次用于将先前状态浅拷贝到下一个状态。不要改变现有状态。 完美运行

以上是关于表值在反应中没有变化的主要内容,如果未能解决你的问题,请参考以下文章

mern - 更新后的值在数据中为空

settings.DEBUG 的值在 Django 测试中的设置和 url 之间变化

没有参数的内联表值函数?

sql2005中 表值函数是啥

MySQL没有表值函数么

sql2005中 表值函数是啥