【问题标题】:React Hook - I always get stale values from useState just because child component never updatesReact Hook - 我总是从 useState 获得陈旧的值,只是因为子组件从不更新
【发布时间】:2019-07-29 19:27:23
【问题描述】:

TL;DR 这是我的父组件:

const Parent = () => {

    const [open, setOpen] = useState([]);

    const handleExpand = panelIndex => {

        if (open.includes(panelIndex)) {
            // remove panelIndex from [...open]
            // asign new array to variable: newOpen
            // set the state

            setOpen(newOpen);

        } else {
            setOpen([...open, panelIndex]);
        }
    }

    return (
      <div>
         <Child expand={handleExpand} /> // No need to update
         <Other isExpanded={open} /> // needs to update if open changed
      </div>
    )
}

这是我的Child 组件:

const Child = (props) => (
   <button
      type="button"
      onClick={() => props.expand(1)}
   >
      EXPAND PANEL 1
   </button>
);

export default React.memo(Child, () => true); // true means don't re-render

这些代码只是一个示例。重点是我不需要更新或重新渲染Child 组件,因为它只是一个按钮。但是我第二次单击该按钮时,它并没有触发 Parent 重新渲染。

如果我像这样将console.log(open) 放入handleExpand

const handleExpand = panelIndex => {
    console.log(open);
    if (open.includes(panelIndex)) {
        // remove panelIndex from [...open]
        // asign new array to variable: newOpen
        // set the state

        setOpen(newOpen);

    } else {
        setOpen([...open, panelIndex]);
    }
}

每次单击按钮时它都会打印出相同的数组,就好像数组中的 open 的值从未更新过一样。

但是如果我让&lt;Child /&gt; 组件在open 更改时重新渲染,它可以工作。这是为什么?这和预期的一样吗?

【问题讨论】:

    标签: javascript reactjs state react-hooks


    【解决方案1】:

    这确实是预期的行为。

    您在这里遇到的是函数闭包。当您将handleExpand 传递给 Child 时,所有引用的变量都将以其当前值“保存”。 open = []。由于您的组件不会重新渲染,因此它不会收到您的 handleExpand 回调的“新版本”。每次调用都会有相同的结果。

    有几种方法可以绕过它。首先显然是让您的 Child 组件重新渲染。

    但是,如果您不想重新渲染,您可以使用useRef创建一个对象并访问它的当前属性:

    const openRef = useRef([])
    const [open, setOpen] = useState(openRef.current);
    
    // We keep our ref value synced with our state value
    useEffect(() => {
      openRef.current = open;
    }, [open])
    
    const handleExpand = panelIndex => {    
        if (openRef.current.includes(panelIndex)) {
            setOpen(newOpen);    
        } else {
            // Notice we use the callback version to get the current state
            // and not a referenced state from the closure
            setOpen(open => [...open, panelIndex]);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-09-22
      • 2020-09-27
      • 1970-01-01
      • 2021-03-10
      • 2021-08-02
      • 2020-12-20
      • 2023-03-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多