React Hooks:重新渲染时的 setState 功能
React Hooks: setState functionality on re-renders
这是一个关于使用挂钩时可能会影响性能的问题。
引用反应文档中的 useState
示例:
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.
关于 useState
的用法,我有两个疑问:
identity is stable and won’t change on re-renders
是什么意思?
- 我可以看到每个按钮都有一个
anonymous
函数作为事件处理程序传递。即使 React 声称的 setState identity is stable
是正确的,匿名函数不会在每次重新渲染时重新创建吗?
如果使用 useCallback
定义记忆函数并将它们用作事件处理程序,效率会不会更高?
将此组件视为问题 1 的示例。
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
// after each render we record the value of setCount
const ref = useRef(null);
useEffect(() => {
ref.current = setCount;
}, [setCount]);
return (
<>
<div>
Did setCount change from since render?{" "}
{(!Object.is(ref.current, setCount)).toString()}
</div>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
这意味着在不同的组件渲染期间 useState 将是相同的 (Object.is)
是的,匿名函数将在每次渲染时 re-created
Wouldn't it be more efficient if useCallback was used to define memoized functions and use them as event handlers?
在这种特殊情况下,不,因为 useCallback 不是免费提供的,而无论如何都会呈现按钮。但是当我们有一个非常重的组件要渲染时,useCallback 会阻止它不必要的 re-renders
- identity is stable and won't change on re-renders 是什么意思?
your setCount method is stable and won't change on re-renders.
- 我可以看到对于每个按钮都有一个匿名函数作为事件处理程序传递。即使 setState 身份是稳定的,正如 React 所声称的那样,匿名函数不会在每个 re-render 处都是 re-created 吗?
You can but here there is no need to do so as you are not passing it to child component, you should use useCallback if you are passing it to another React component.
What does identity is stable and won’t change on re-renders mean ?
useState
返回的函数在渲染周期中不会改变。也就是说,第一个渲染周期返回的调度函数仍然可以在第 10 个渲染周期之后调用以设置状态。这允许您在任何时候使用调度函数设置挂钩,而无需在函数引用更改时刷新挂钩。
useEffect(() => {
setCount(initialCount);
}, [ initialCount, setCount ]); // <--- setCount is not needed here
I can see that for each button an anonymous function is passed as event handler. Even if setState identity is stable as claimed by React is true, wouldn't the anonymous function be re-created at every re-render ?
是的,箭头函数确实将在 re-render 上重建。另一种方法是使用 useCallback
来记住回调,但代价是什么?调用 useCallback
的成本、记忆该回调的成本、构建对它的引用的成本以及在每个 re-render 上检索该回调的成本大大超过了在每个 [= 上简单地构建一个函数的好处。 =26=].
useCallback
函数本身是 20 lines long 以及其他 3 个对其他内部 React API 的嵌套函数调用。所有这些都是为了防止在每个渲染器上都使用单行功能?数学根本不支持 useCallback
。唯一有用的场景是当你希望你的回调通过引用或其他机制有一个 "stable identity" 时,这样你就可以将回调作为 props 传递而不会导致过多的 re-renders.
这是一个关于使用挂钩时可能会影响性能的问题。
引用反应文档中的 useState
示例:
function Counter({initialCount}) {
const [count, setCount] = useState(initialCount);
return (
<>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.
关于 useState
的用法,我有两个疑问:
identity is stable and won’t change on re-renders
是什么意思?- 我可以看到每个按钮都有一个
anonymous
函数作为事件处理程序传递。即使 React 声称的setState identity is stable
是正确的,匿名函数不会在每次重新渲染时重新创建吗?
如果使用 useCallback
定义记忆函数并将它们用作事件处理程序,效率会不会更高?
将此组件视为问题 1 的示例。
function Counter({ initialCount }) {
const [count, setCount] = useState(initialCount);
// after each render we record the value of setCount
const ref = useRef(null);
useEffect(() => {
ref.current = setCount;
}, [setCount]);
return (
<>
<div>
Did setCount change from since render?{" "}
{(!Object.is(ref.current, setCount)).toString()}
</div>
Count: {count}
<button onClick={() => setCount(initialCount)}>Reset</button>
<button onClick={() => setCount(prevCount => prevCount + 1)}>+</button>
<button onClick={() => setCount(prevCount => prevCount - 1)}>-</button>
</>
);
}
这意味着在不同的组件渲染期间 useState 将是相同的 (Object.is)
是的,匿名函数将在每次渲染时 re-created
Wouldn't it be more efficient if useCallback was used to define memoized functions and use them as event handlers?
在这种特殊情况下,不,因为 useCallback 不是免费提供的,而无论如何都会呈现按钮。但是当我们有一个非常重的组件要渲染时,useCallback 会阻止它不必要的 re-renders
- identity is stable and won't change on re-renders 是什么意思?
your setCount method is stable and won't change on re-renders.
- 我可以看到对于每个按钮都有一个匿名函数作为事件处理程序传递。即使 setState 身份是稳定的,正如 React 所声称的那样,匿名函数不会在每个 re-render 处都是 re-created 吗?
You can but here there is no need to do so as you are not passing it to child component, you should use useCallback if you are passing it to another React component.
What does identity is stable and won’t change on re-renders mean ?
useState
返回的函数在渲染周期中不会改变。也就是说,第一个渲染周期返回的调度函数仍然可以在第 10 个渲染周期之后调用以设置状态。这允许您在任何时候使用调度函数设置挂钩,而无需在函数引用更改时刷新挂钩。
useEffect(() => {
setCount(initialCount);
}, [ initialCount, setCount ]); // <--- setCount is not needed here
I can see that for each button an anonymous function is passed as event handler. Even if setState identity is stable as claimed by React is true, wouldn't the anonymous function be re-created at every re-render ?
是的,箭头函数确实将在 re-render 上重建。另一种方法是使用 useCallback
来记住回调,但代价是什么?调用 useCallback
的成本、记忆该回调的成本、构建对它的引用的成本以及在每个 re-render 上检索该回调的成本大大超过了在每个 [= 上简单地构建一个函数的好处。 =26=].
useCallback
函数本身是 20 lines long 以及其他 3 个对其他内部 React API 的嵌套函数调用。所有这些都是为了防止在每个渲染器上都使用单行功能?数学根本不支持 useCallback
。唯一有用的场景是当你希望你的回调通过引用或其他机制有一个 "stable identity" 时,这样你就可以将回调作为 props 传递而不会导致过多的 re-renders.