[英]How to avoid triggering useEffect on every render?
I am creating a custom hook that accepts an object and in turn calls useEffect
.我正在创建一个接受对象并依次调用
useEffect
的自定义挂钩。 The object can contain inline functions.该对象可以包含内联函数。
const stuff = useValidation({
fields: {
username: { /* more nested objects */ }
},
onSubmit: () => alert('submitted'),
});
The hook implementation looks like this:钩子实现如下所示:
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields, state]);
}
There's more to it ( here's the actual implementation ), but these are the relevant parts.还有更多(这里是实际的实现),但这些是相关的部分。
When I create the object inline, the useEffect
runs continuously.当我内联创建对象时,
useEffect
连续运行。 This happens because React uses reference equality (not deep equality) to check whether or not stuff has changed.发生这种情况是因为 React 使用引用相等(不是深度相等)来检查内容是否发生了变化。
I can "fix" this by either wrapping my config in useMemo
, or move it outside of the render method.我可以通过将我的配置包装在
useMemo
中或将其移出渲染方法来“修复”此问题。 Both of these are pretty bad for developer experience.这两者对于开发者体验来说都非常糟糕。
I tried Kent C. Dodds' use-deep-compare-effect
library, but since I'm allowing inline arrow functions in my config, it doesn't "work".我尝试了 Kent C. Dodds 的
use-deep-compare-effect
库,但由于我在我的配置中允许内联箭头函数,所以它不起作用。
Preferably, I'd love to be able to let the user input an inline object, and let me deal with any changes somehow.最好,我希望能够让用户输入一个内联对象,并让我以某种方式处理任何更改。
How can I solve this?我该如何解决这个问题?
It seems to me that useEffect
is called every render because the config you pass to useValidation
is created on the fly every time.在我看来,每次渲染都会调用
useEffect
,因为你传递给useValidation
的配置每次都是动态创建的。 My suggestion would be to put this in a state somewhere either in your component where you use useValidation
or within the useValidation
itself like so:我的建议是将其置于使用
useValidation
的组件中或useValidation
本身内的某处状态,如下所示:
function useValidation(config) {
const [storedConfig, setStoredConfig] = useState(config);
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [storedConfig.fields, state]);
}
If the config is changeable then you should have it stored outside of the hook, either way make sure the config isn't a new object every render.如果配置是可变的,那么你应该将它存储在钩子之外,无论哪种方式确保配置不是每次渲染的新对象。
According to the documentation you should not put objects or arrays on the array, but the individual attributes inside it, like this:根据文档,您不应将对象或数组放在数组上,而应将其放在其中的各个属性,如下所示:
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields.username, state]);
}
I don't know what your state
is, but should be an immutable value such as a string, number, boolean, etc.我不知道你的
state
是什么,但应该是一个不可变的值,比如字符串、数字、布尔值等。
Same thing with Date
objects, they should be casted to String
first. Date
对象也一样,它们应该首先转换为String
。
looks like it's only Syntax Error in your code.看起来它只是代码中的语法错误。
your function should look like this你的功能应该是这样的
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields, state])
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.