表值在反应中没有变化
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
状态。再次检查代码框。功能状态更新再次用于将先前状态浅拷贝到下一个状态。不要改变现有状态。
完美运行以上是关于表值在反应中没有变化的主要内容,如果未能解决你的问题,请参考以下文章