Почему useCallback с пустым массивом зависимостей не возвращает ту же функцию?
Я пытаюсь написать собственный перехватчик React, который возвращает функции, поддерживающие равенство ссылок при каждом вызове перехватчика. Это означает, что каждый раз от хука возвращается одна и та же функция, так что сравнение их с===
возвращается true
.
У меня создалось впечатление, что useCallback
крючок был способом добиться этого:
function useCorrectCallback() {
const [count, setCount] = useState(0)
let increment = () => setCount(c => c + 1)
let memoized = useCallback(increment, [])
return {
count,
increment: memoized
}
}
Поэтому, когда этот хук вызывается, я считаю, что increment
свойство возвращаемого значения должно каждый раз быть одной и той же функцией. Это должно быть значение встроенной функции при первом запуске ловушки и не меняться при последующих выполнениях ловушки, потому что я не указал никаких зависимостей дляuseCallback
с []
.
Но похоже, что это не так! Я написал тестовый проект, чтобы продемонстрировать эту проблему. Вот суть этого теста:
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)
}
Чтобы убедиться, что мои тесты точны, я также написал ловушку, которая просто использует объект с глобальной областью видимости для поддержания "памяти" вместо того, чтобы пытаться попросить 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
вернуть другую функцию в свой increment
имущество при последующих казнях?
1 ответ
Я подозреваю, что проблема в 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>
)
})