为什么具有空依赖项数组的 useCallback 不是 return 相同的函数?
Why does useCallback with an empty dependency array not return the same function?
我正在尝试编写一个自定义 React 钩子,该钩子 returns 函数在每次调用钩子时保持引用相等。这意味着完全相同的函数每次都从钩子中 returned,这样就可以将它们与 ===
returns true
.
进行比较
我的印象是 useCallback
hook 是实现该目标的方法:
function useCorrectCallback() {
const [count, setCount] = useState(0)
let increment = () => setCount(c => c + 1)
let memoized = useCallback(increment, [])
return {
count,
increment: memoized
}
}
所以当这个钩子被调用时,我相信 return 值的 increment
属性 每次都应该是完全相同的函数。它应该是第一次钩子 运行 时内联函数的值,并且在后续执行钩子时不会改变,因为我没有指定 useCallback
和 []
的依赖关系。
但事实并非如此!我写了一个 test project to demonstrate this problem. Here's the crux of that test:
function validateFunctionEquality(hookResult) {
// Store the last result of running the hook
let stored = { ...hookResult }
// Force a re-render to run the hook again
expect(hookResult.count).toEqual(0)
act(hookResult.increment)
expect(hookResult.count).toEqual(1)
// Compare the previous results to the current results
expect(hookResult.constant).toEqual(stored.constant)
expect(hookResult.increment).toEqual(stored.increment)
}
只是为了验证我的测试是准确的,我还写了一个钩子,它只使用一个全局范围的对象来维护 "memory" 而不是试图让 React 用 useCallback
来做它。这个钩子通过了测试:
let memoryHack = {}
function useMemoryHack() {
const [count, setCount] = useState(0)
let increment = () => setCount(c => c + 1)
memoryHack.increment = memoryHack.increment || increment
return {
count,
increment: memoryHack.increment
}
}
我是不是用错了useCallback
?为什么 useCorrectCallback
return 在其 increment
属性 的后续执行中有不同的功能?
我怀疑是 enzyme
的浅层问题。可能与 https://github.com/airbnb/enzyme/issues/2086
有关
通过使用 mount
,您的测试按原样通过:
act(() => {
componentMount = mount( // used mount instead of shallow
<Component>
{hookValues => {
copyHookValues(hookResult, hookValues)
return null
}}
</Component>
)
})
我正在尝试编写一个自定义 React 钩子,该钩子 returns 函数在每次调用钩子时保持引用相等。这意味着完全相同的函数每次都从钩子中 returned,这样就可以将它们与 ===
returns true
.
我的印象是 useCallback
hook 是实现该目标的方法:
function useCorrectCallback() {
const [count, setCount] = useState(0)
let increment = () => setCount(c => c + 1)
let memoized = useCallback(increment, [])
return {
count,
increment: memoized
}
}
所以当这个钩子被调用时,我相信 return 值的 increment
属性 每次都应该是完全相同的函数。它应该是第一次钩子 运行 时内联函数的值,并且在后续执行钩子时不会改变,因为我没有指定 useCallback
和 []
的依赖关系。
但事实并非如此!我写了一个 test project to demonstrate this problem. Here's the crux of that test:
function validateFunctionEquality(hookResult) {
// Store the last result of running the hook
let stored = { ...hookResult }
// Force a re-render to run the hook again
expect(hookResult.count).toEqual(0)
act(hookResult.increment)
expect(hookResult.count).toEqual(1)
// Compare the previous results to the current results
expect(hookResult.constant).toEqual(stored.constant)
expect(hookResult.increment).toEqual(stored.increment)
}
只是为了验证我的测试是准确的,我还写了一个钩子,它只使用一个全局范围的对象来维护 "memory" 而不是试图让 React 用 useCallback
来做它。这个钩子通过了测试:
let memoryHack = {}
function useMemoryHack() {
const [count, setCount] = useState(0)
let increment = () => setCount(c => c + 1)
memoryHack.increment = memoryHack.increment || increment
return {
count,
increment: memoryHack.increment
}
}
我是不是用错了useCallback
?为什么 useCorrectCallback
return 在其 increment
属性 的后续执行中有不同的功能?
我怀疑是 enzyme
的浅层问题。可能与 https://github.com/airbnb/enzyme/issues/2086
通过使用 mount
,您的测试按原样通过:
act(() => {
componentMount = mount( // used mount instead of shallow
<Component>
{hookValues => {
copyHookValues(hookResult, hookValues)
return null
}}
</Component>
)
})