我正在创建一个接受对象的自定义挂钩,然后依次调用useEffect
。该对象可以包含内联函数。
const stuff = useValidation({
fields: {
username: { /* more nested objects */ }
},
onSubmit: () => alert('submitted'),
});
挂钩实现如下:
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields, state]);
}
还有更多内容(here's the actual implementation),但这是相关的部分。
当我内联创建对象时,useEffect
连续运行。发生这种情况是因为React使用引用相等(不是深度相等)来检查内容是否已更改。
我可以通过将配置文件包装在useMemo
中或将其移动到render方法之外来“修复”此问题。两者都对开发人员的体验不利。
我尝试了Kent C. Dodds的use-deep-compare-effect
库,但是由于我在配置中允许使用内联箭头功能,因此它“无法工作”。
最好,我希望能够让用户输入一个内联对象,并让我以某种方式处理所有更改。
我该如何解决?
答案 0 :(得分:1)
在我看来,useEffect
被称为每个渲染,因为传递给useValidation
的配置是每次动态创建的。我的建议是将其置于您使用useValidation
的组件中或useValidation
本身中的某个位置,就像这样:
function useValidation(config) {
const [storedConfig, setStoredConfig] = useState(config);
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [storedConfig.fields, state]);
}
如果配置是可更改的,则应将其存储在钩子之外,无论哪种方式,都要确保该配置不是每个渲染的新对象。
答案 1 :(得分:0)
根据文档,您不应将对象或数组放在数组上,而应将其中的各个属性放在其中,如下所示:
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields.username, state]);
}
我不知道您的 state
是什么,但应该是一个不可变的值,例如字符串、数字、布尔值等。
与 Date
对象相同,它们应该首先转换为 String
。
答案 2 :(得分:-1)
看起来只是代码中的唯一语法错误。
您的函数应如下图所示
function useValidation(config) {
const [state, dispatch] = useReducer(validationReducer);
useEffect(() => {
validateFields(config.fields, state);
}, [config.fields, state])
}