在react文档中,我们可以找到:
注意
React保证setState函数身份稳定,并且在重新渲染时不会更改。这就是为什么可以安全地从useEffect或useCallback依赖项列表中省略的原因。
有时,自定义钩子还可以确保返回的函数身份稳定,是否可以让React知道呢?
在与Jayce444讨论后添加:
如果反应没有将自定义钩子的返回值视为稳定的身份,但是我们从其他钩子的依赖项列表中忽略了它,则npm将报告警告
答案 0 :(得分:1)
在您的情况下,您实际上并不想只为自定义代码隐藏该警告。 React为setState函数执行此操作,因为它引用了自己库中的某些内容。正如评论者所提到的,您可以为该特定行禁用掉毛规则,但是最好包括此依赖项。
编写代码时,通常希望将代码与其上下文松散地耦合在一起,而不会对实际使用位置进行任何假设。在当前用例中,您知道钩子中的函数没有更改,将来可能会更改。考虑以下示例:
const useCustomHook = () => {
const calculate = useCallback((number) => {
// Do stuff here
}, []);
return ({ calculate });
};
const MyComponent = () => {
const [number, setNumber] = useState(0);
const { calculate } = useCustomHook();
useEffect(() => {
calculate(number);
}, [number]);
// rest of the component
};
一个简单的示例,您有一个自定义挂钩返回的记忆calculate
函数,以及一个处于组件状态的数字。当数字更改时,请重新计算。您会看到,正如您希望在用例中所做的那样,我们已将calculate
排除在useEffect
依赖之外。
但是,可以说这发生了变化,我们用这个替换了自定义钩子:
const useCustomHook = () => {
const someValue = useContext(someRandomContext);
const calculateOne = (number) => {/* some code */};
const calculateTwo = (number) => {/* some code */};
const calculate = useCallback(someValue ? calculateOne : calculateTwo, [someValue]);
return ({ calculate });
};
现在,当上下文值更改时,calculate函数也更改。但是,如果您组件的useEffect
中没有这种依赖关系,则实际上不会触发计算,并且您的状态现在将具有陈旧/不正确的值。
尽管从技术上讲,目前具有这种依赖关系可能是多余的,但如果您进行防御性编程,则可以避免类似的错误,而这些错误可能会使您难以追查。尤其是由于有依赖关系链,使用自定义钩子以及使用其他钩子的钩子等都可以获得。从字面上看,您的依赖项数组中有一些额外的字符,最好只是添加它,避免日后出现麻烦
答案 1 :(得分:0)
@ Jayce444,非常感谢,我知道您的选择。
我的目标是非常像useState一样声明钩子,ThisHook = useState + immer(https://github.com/immerjs/immer)
这是我的自定义钩子
import produce, { Draft } from "immer";
import { useCallback, useState } from "react";
export type DraftMutation<T> = (draft: Draft<T>) => void;
export function useImmerState<T>(
initialValue: T
): [T, (mutation: DraftMutation<T>) => void] {
const [value, setValue] = useState(initialValue);
const setValueByImmer = useCallback((mutation: DraftMutation<T>) => {
setValue(oldValue => {
return produce(oldValue, draft => mutation(draft));
});
}, []);
return [value, setValueByImmer];
}
然后,我们讨论如何使用它。
Setp 1,定义一个简单的类型,如下所示:
interface Point {
readonly x: number;
readonly y: number;
}
Setp 2,使用我的自定义钩子是功能组件
const [point, setPoint] = useImmerState<Point>({x: 0, y: 0});
const onButtonClick = useCallback(() => {
setPoint(draft => {
draft.x++;
draft.y++;
});
}, []); //Need not add 'setPoint' into the dependency list, and no eslint warining should appear
您的演示非常出色,但是此挂钩可以保证没有问题。这个钩子看起来非常像useState,这就是为什么我想要这个未来。如果开发人员知道他/她在做什么,React应该支持它。