reactjs - React 不会在数组状态更新时重新渲染

标签 reactjs react-hooks material-ui

我正在尝试制作 3 个按钮控件来打开和关闭 3 个相应的菜单列表。 Material-UI 是我目前使用的 UI 框架。这是代码:


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

我检查了控制台中的值更新,它们看起来不错,但我不确定为什么 React 不会重新呈现页面(当我单击按钮时,没有任何反应,但 anchor 状态已更新)。感谢您的帮助。

最佳答案

你正在做的是一个突变:

arr[index] = event.target

更新状态时应避免突变。因为如果你改变你的状态,React 无法理解你的状态已经改变。您可以使用 mapfilter 或任何其他不会改变您的状态的方法。

const handleClick = (event, index) => {
  setAnchors((prev) =>
    prev.map((el, i) => {
      if (i !== index) {
        return el;
      }

      return event.target;
    })
  );
};

或者如果你喜欢简洁的:

const handleClick = (event, index) => {
  setAnchors((prev) => prev.map((el, i) => (i !== index ? el : event.target)));
};

展开语法可用于非嵌套数组,但如果您正在处理嵌套数组并更改嵌套值,请务必小心,因为展开语法会创建浅拷贝。这就是为什么我喜欢在大多数时候使用像 map 这样的方法。

如果你不想映射整个数组(有些人更喜欢这样)Object.assign 和 spread syntax 可以一起使用。

const handleClick = (event, index) => {
  setAnchors((prev) => Object.assign([], { ...prev, [index]: event.target }));
};

更新:

正如我之前解释的那样,传播语法只会生成浅拷贝。

Note: Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays, as the following example shows. (The same is true with Object.assign() and spread syntax.)

Source

这意味着嵌套值与原始值保持相同的引用。因此,如果您为新数组(或对象)更改某些内容,它也会更改原始数组。

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

如您所见,我们的原始数组也发生了变化。实际上,这不是嵌套数组,但我们正在更改数组元素的嵌套属性。也许这是嵌套数组的更好示例,但上面的示例更现实。

const arr = [["foo", "bar"], [1,2]];

const newArr = [...arr];

newArr[0][0] = "fizz";

console.log(newArr);
console.log(arr);

关于reactjs - React 不会在数组状态更新时重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64982593/

相关文章:

reactjs - React Router 的 useParams 导致 useEffect 重新运行

reactjs - 是否可以为事件处理程序推断useCallback的类型签名?

javascript - `for` 循环 vs `.map` 迭代数组

reactjs - 批处理钩子(Hook)请求并等待它们在 React 中全部完成

reactjs - 如何在 react 中处理自定义 Hook 的依赖关系数组

javascript - 通过 HOC 提供数据,但调用组件时出现 Property '' is Missing in type '{}' but required in type '' 错误

javascript - React autoFocus 将光标设置为输入值的开头

javascript - 根据路线 react 路由器导航栏

reactjs - 通过扩展排版在 React 中使用 Material UI 进行 i18n 本地化?

html - 更改 "overflow avatar"的大小以匹配 AvatarGroup 中的其他头像