[英]React doesn't rerender on an array state update
I'm trying to make 3 button controls to open and close 3 corresponding menu lists.我正在尝试制作 3 个按钮控件来打开和关闭 3 个相应的菜单列表。 Material-UI is the UI framework I'm currently using. Material-UI 是我目前使用的 UI 框架。 Here is the code:这是代码:
const Filters = () => {
const [anchors, setAnchors] = useState([null, null, null])
const handleClick = (event, index) => {
const arr = anchors
arr[index] = event.target
setAnchors(arr)
}
const handleClose = (index) => {
const arr = anchors
arr[index] = null
setAnchors(arr)
}
return(
<div id="top-filters">
<div className="controls">
<Button onClick={(event) => handleClick(event, 0)}>Sort By</Button>
<Button onClick={(event) => handleClick(event, 1)}>Price</Button>
<Button onClick={(event) => handleClick(event, 2)}>Delivery Fees</Button>
</div>
{
console.log({anchors})
}
<Menu key={1}
anchorEl={anchors[0]}
open={Boolean(anchors[0])}
onClose={() => handleClose(0)}
keepMounted
>
<MenuItem>
<ListItemText primary="By Rating" />
</MenuItem>
</Menu>
<Menu key={2}
anchorEl={anchors[1]}
open={Boolean(anchors[1])}
onClose={() => handleClose(1)}
keepMounted
>
<MenuItem>
<Slider defaultValue={25} marks={marks} step={25} />
</MenuItem>
</Menu>
<Menu key={3}
anchorEl={anchors[2]}
open={Boolean(anchors[2])}
onClose={() => handleClose(2)}
keepMounted
>
<MenuItem>
<ListItemText primary="By Delivery Fees" />
</MenuItem>
</Menu>
<FormControl className="search-bar-filter">
<Icon>search</Icon>
<StyledInput classes={{ root: classes.root }} name="search" type="search" placeholder="Search" disableUnderline />
</FormControl>
</div>
)
}
export default Filters
I checked the values update in console, they look fine, but I'm not sure why React won't rerender the page (when I click the buttons, nothing happens but anchors state is updated).我检查了控制台中的值更新,它们看起来不错,但我不确定为什么 React 不会重新渲染页面(当我单击按钮时,没有任何反应,但锚点状态已更新)。 Thanks for help.感谢帮助。
What you are doing there is a mutation:你在做什么有一个突变:
arr[index] = event.target
You should avoid mutation when updating your state.更新状态时应避免突变。 Because if you mutate your state React can not understand your state has changed.因为如果你改变你的状态,React 无法理解你的状态已经改变。 You can use methods like map
, filter
or any other method which do not mutate your state.您可以使用map
、 filter
或任何其他不会改变您的状态的方法。
const handleClick = (event, index) => {
setAnchors((prev) =>
prev.map((el, i) => {
if (i !== index) {
return el;
}
return event.target;
})
);
};
or if you like a concise one:或者如果你喜欢简洁的:
const handleClick = (event, index) => {
setAnchors((prev) => prev.map((el, i) => (i !== index ? el : event.target)));
};
The spread syntax can be used for non-nested arrays, but if you are working on nested arrays and changing the nested values just be careful since spread syntax creates shallow copies.展开语法可用于非嵌套数组,但如果您正在处理嵌套数组并更改嵌套值,请小心,因为展开语法会创建浅拷贝。 This is why I like to to use methods like map
most of the time.这就是为什么我大部分时间都喜欢使用像map
这样的方法。
If you don't want to map all over the array (some prefers this) Object.assign
and spread syntax can be used together.如果您不想映射整个数组(有些人更喜欢这样),可以一起使用Object.assign
和 spread 语法。
const handleClick = (event, index) => {
setAnchors((prev) => Object.assign([], { ...prev, [index]: event.target }));
};
Update:更新:
As I explained before, spread syntax only makes shallow copies.正如我之前解释过的,传播语法只会制作浅拷贝。
Note: Spread syntax effectively goes one level deep while copying an array.注意:在复制数组时,Spread 语法有效地深入一层。 Therefore, it may be unsuitable for copying multidimensional arrays, as the following example shows.因此,它可能不适合复制多维数组,如下例所示。 (The same is true with Object.assign() and spread syntax.) (同样适用于 Object.assign() 和 spread 语法。)
This means nested values keep the same references as the original ones.这意味着嵌套值与原始值保持相同的引用。 So, if you change something for the new array (or object) it also changes the original one.因此,如果您为新数组(或对象)更改某些内容,它也会更改原始数组。
const arr = [ { id: 0, name: "foo" }, { id: 1, name: "bar" }, { id: 2, name: "baz" }, ]; const newArr = [...arr]; newArr[0].name = "something else"; console.log("newArr", newArr); console.log("original arr", arr);
As you can see our original array also changed.如您所见,我们的原始数组也发生了变化。 Actually, this isn't a nested array but we are changing a nested property for the array element.实际上,这不是嵌套数组,但我们正在更改数组元素的嵌套属性。 Maybe this is a better example for nested arrays, but the example above is more realistic.也许这是嵌套数组的一个更好的例子,但上面的例子更现实。
const arr = [["foo", "bar"], [1,2]]; const newArr = [...arr]; newArr[0][0] = "fizz"; console.log(newArr); console.log(arr);
You are wrongly updating the state.您错误地更新了状态。 const arr = anchors
is not the correct way to clone the anchors. const arr = anchors
不是克隆锚点的正确方法。 You need to use ...
operator.您需要使用...
运算符。
const handleClick = (event, index) => {
const arr = [... anchors]
arr[index] = event.target
setAnchors(arr)
}
const handleClose = (index) => {
const arr = [... anchors]
arr[index] = null
setAnchors(arr)
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.