简体   繁体   English

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

[英]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.您可以使用mapfilter或任何其他不会改变您的状态的方法。

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 语法。)

Source 来源

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.

相关问题 React挂钩不会在状态更新时重新呈现 - React hook doesn't rerender on state update React 不会在 state 更新上重新渲染 - React doesn't rerender on state update 更新到状态后,React组件不会重新渲染 - React component doesn't rerender after update to state React 状态不起作用,它不会重新渲染组件 - React state doesn't work, it doesn't rerender components React / Nextjs:基于状态数组的.map()输出不会重新渲染,因为键不会改变 - React / Nextjs: .map() output based on state array doesn't rerender because of keys don't change 如何使用Apollo Query构造React代码,以使对象的随机查询数组不会随着状态变化而重新呈现? - How to structure React code with Apollo Query so that a random queried array of objects doesn't rerender with state change? 在 React 中推迟 state 更新/重新渲染 - Defer state update / rerender in React State 更新不会触发条件渲染组件中的重新渲染 - State update doesn't trigger rerender in conditional rendering component React Native:通过外部函数更改状态不会重新渲染 - React Native: changing state via external function doesn't rerender Safari 中的状态更改后,React 组件不会重新渲染 - React component doesn't rerender after state change in Safari
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM