簡體   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