【问题标题】:How to Slow Down React State Update Intentionally - Batch Updates如何故意减慢 React 状态更新 - 批量更新
【发布时间】:2022-07-13 23:01:57
【问题描述】:

有时我可能想卸载并重新安装一个包含新数据的组件。这可能看起来像:

setAllPosts(undefined);
setAllPosts(newArrayOfPosts);

因为 React 批处理状态变化,取决于 newArrayOfPosts 来自哪里,状态不会改变。我已经能够破解一个 setTimeout() 为 1 秒的解决方案,然后填写 setAllPosts(),但这感觉很不对。

有没有一种最佳实践方法来告诉 React 放慢速度?或者可能不批量更新这个特定的状态变化?

附:我知道有更好的方法可以做到这一点,但我在第三方环境中工作,并且非常受限于我可以访问的内容。

【问题讨论】:

    标签: reactjs state


    【解决方案1】:

    一旦 react 18 可用(它目前是一个候选版本),就会有一个函数可以强制更新不被批处理:flushSync

    import { flushSync } from 'react-dom';
    
    flushSync(() => {
      setAllPosts(undefined);
    });
    flushSync(() => {
      setAllPosts(newArrayOfPosts);
    });
    

    在此之前,您可能需要执行 setTimeout 方法(尽管它不需要是一整秒)。

    附:我知道有更好的方法可以做到这一点,但我在第三方环境中工作,并且非常受限于我可以访问的内容。

    是的,如果你能做点别的事情可能会更好。大多数情况下,如果您想有意卸载/重新安装组件,最好使用key 来实现,当您希望重新安装时更改该key

    const [key, setKey] = useState(0);
    const [allPosts, setAllPosts] = useState([]);
    
    // ...
    setKey(prev => prev + 1);
    setAllPosts(newArrayOfPosts);
    
    // ...
    return (
       <SomeComponent key={key} posts={allPosts} />
    )
    

    【讨论】:

    • 你的“不需要一秒钟”的评论真的让我笑了。感谢您的想法,我期待阅读有关 flushSync 的内容!
    【解决方案2】:

    有时我可能想卸载并重新安装一个包含新数据的组件。

    听起来这个用例需要一个useEffect(),它的依赖关系基于你关心的东西,比如向这个组件提供的另一条状态或道具。

    useEffect(() => {
       setAllPosts(newArrayOfPosts);
    }, [shouldUpdate]);
    

    我什至见过有人触发 useEffect() 的例子,它依赖于称为 countrenderCount 的状态。不确定这是否一定是最佳实践,但这是一种处理方式。

    const [count, setCount] = useState(0);
    const [allPosts, setAllPosts] = useState([]);
    
    useEffect(() => {
       setAllPosts(props.values);
    }, [count]);
    
    const handleChange = () => {
       setCount(prevCount => prevCount + 1); // This will trigger your useEffect when handleChange() in invoked
    }
    

    【讨论】:

    • 这绝对可行,但不适用于这个特定的环境。我正在将一个组件注入一个已经建立的网上商店,它有点时髦。不过非常感谢。
    • 啊,明白了。祝你好运!
    【解决方案3】:

    你可以这样做 -

    import { flushSync } from 'react-dom';
    
    const handleClick = () => {
      flushSync(() => {
        setAllPosts(undefined);
      // react will create a re-render here
      });
      
      flushSync(() => {
        setAllPosts(newArrayOfPosts);
      // react will create a re-render here
      });
    };
    

    这用于取消批处理反应状态。这只是一种方法。另一种方法是使用setTimeout。请注意,在第 18 版的 react 中,setTimeouts 中的状态更新也会被批处理 - 这被称为自动批处理,但我们仍然可以通过使用不同的 setTimeouts 来实现这一点 -

    const handleClick = () => {
      setTimeout(() => {
        setAllPosts(undefined);
      // react will create a re-render here
      }, 10);
      
      setTimeout(() => {
        setAllPosts(newArrayOfPosts);
      // react will create a re-render here
      },20);
    };
    

    只需确保保持时间差以排除 React 完成的批处理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 2021-03-29
      • 2017-08-02
      • 2020-08-07
      • 1970-01-01
      • 2023-03-16
      相关资源
      最近更新 更多