繁体   English   中英

如何故意减慢 React 状态更新 - 批量更新

[英]How to Slow Down React State Update Intentionally - Batch Updates

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

setAllPosts(undefined);
setAllPosts(newArrayOfPosts);

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

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

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

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

import { flushSync } from 'react-dom';

flushSync(() => {
  setAllPosts(undefined);
});
flushSync(() => {
  setAllPosts(newArrayOfPosts);
});

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

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

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

const [key, setKey] = useState(0);
const [allPosts, setAllPosts] = useState([]);

// ...
setKey(prev => prev + 1);
setAllPosts(newArrayOfPosts);

// ...
return (
   <SomeComponent key={key} posts={allPosts} />
)

这就是你可以做到的 -

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 完成的批处理。

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

听起来这个用例调用了一个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
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM