React Redux不会通过两个背靠背的操作重新渲染组件



我有一个组件,它用useSelector侦听Redux存储中的某个值。每当值发生变化时,它都应该重新渲染。不过,当我将两个操作紧接在一起调度时,它会跳过第一个值更改,不会重新渲染组件。

我可以通过将两个调度调用封装在一个setTimout(…, 0)中来解决这个问题。但这可能是一个肮脏的变通方法,我想知道是什么导致了这种与我的期望不匹配。

在这个CodePen中可以找到一个最小的例子:https://codepen.io/lenzls/pen/GRMYJMz?editors=1011

摘录

function StatusDisplay () {
const comparisonFunc = (newSelectedState, latestSelectedState) => {
const equality = newSelectedState === latestSelectedState
console.log(`[StatusDisplay] — Call comparisonFunc — new: ${newSelectedState} | old: ${latestSelectedState} | equal?: ${equality}`)
return equality
}
const status = useSelector(state => state.status, comparisonFunc)
console.log(`[StatusDisplay] — !!render component — status: ${status}`)

return <div>UpdatTestComp {status}</div>
}
function App () {
const changeState = () => {
console.warn(`PRESSING BUTTON`)
console.log(`Dispatch status = empty — Expecting [StatusDisplay] to rerender…`)
store.dispatch({type: 'CHANGE', payload: 'empty'});
console.log(`Dispatch status = error — Expecting [StatusDisplay] to rerender…`)
store.dispatch({type: 'CHANGE', payload: 'error'});
}

const changeStateAfterTimeout = () => setTimeout(changeState, 0)
return (
<div>
<button onClick={changeState}>dispatch two actions</button>
<button onClick={changeStateAfterTimeout}>dispatch two actions after timeout</button>
<StatusDisplay />
</div>
);
}

示例

页面加载时,初始状态为error。控制台打印

"Initial status: error"
"[StatusDisplay] — !!render component — status: error"

然后我按下dispatch two actions按钮。控制台打印

"PRESSING BUTTON"
"Dispatch status = empty — Expecting [StatusDisplay] to rerender…"
"[StatusDisplay] — Call comparisonFunc — new: empty | old: error | equal?: false"
"Dispatch status = error — Expecting [StatusDisplay] to rerender…"
"[StatusDisplay] — Call comparisonFunc — new: error | old: empty | equal?: false"
"[StatusDisplay] — Call comparisonFunc — new: error | old: error | equal?: true"
"[StatusDisplay] — !!render component — status: error"

我们看到useSelector的比较函数实际上是在状态更改之后(第二次操作之前(立即调用的,但组件仍然没有重新渲染。

如果我按下dispatch two actions after timeout按钮,控制台将打印

"PRESSING BUTTON"
"Dispatch status = empty — Expecting [StatusDisplay] to rerender…"
"[StatusDisplay] — Call comparisonFunc — new: empty | old: error | equal?: false"
"[StatusDisplay] — Call comparisonFunc — new: empty | old: empty | equal?: true"
"[StatusDisplay] — !!render component — status: empty"
"Dispatch status = error — Expecting [StatusDisplay] to rerender…"
"[StatusDisplay] — Call comparisonFunc — new: error | old: empty | equal?: false"
"[StatusDisplay] — Call comparisonFunc — new: error | old: error | equal?: true"
"[StatusDisplay] — !!render component — status: error"

在这种情况下,组件实际上渲染两次,每次更改status都渲染一次。无论在哪种情况下,这都是我所期望的。


我假设Redux的dispatch实际上是同步的,正如这里所描述的,但react Redux中正在进行一些优化。不过,我在文档中找不到有关它的信息。

总的来说,我的实际例子比上面的要间接一点,而且这两个动作并没有从字面上前后改变同一件事。

这是预期行为。React和React Redux将把这些分派批处理在一起,因为它们都发生在同一事件处理程序和同一事件循环中。因此,这将有意只导致使用最终状态进行一次重新渲染。

如果您将处理程序更改为在超时后运行,React 17不会自动将这些更新批处理在一起。但是,React 18对它们进行批处理。通过在从React-Redux导出的batch()API中包装两个分派,您可以使用React17获得类似的行为

相关内容

  • 没有找到相关文章

最新更新