Javascript 如何避免在每次渲染时触发useEffect?

Javascript 如何避免在每次渲染时触发useEffect?,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我正在创建一个自定义挂钩,它接受一个对象,并依次调用useffect。对象可以包含内联函数 const stuff=useValidation({ 字段:{ 用户名:{/*更多嵌套对象*/} }, onSubmit:()=>警报(“已提交”), }); 钩子实现如下所示: function useValidation(config) { const [state, dispatch] = useReducer(validationReducer); useEffect(() =>

我正在创建一个自定义挂钩,它接受一个对象,并依次调用
useffect
。对象可以包含内联函数

const stuff=useValidation({
字段:{
用户名:{/*更多嵌套对象*/}
},
onSubmit:()=>警报(“已提交”),
});
钩子实现如下所示:

function useValidation(config) {
  const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields.username, state]);
}
函数使用验证(配置){
const[state,dispatch]=useReducer(validationReducer);
useffect(()=>{
validateFields(配置字段、状态);
},[config.fields,state]);
}
还有更多内容(),但这些都是相关的部分

当我内联创建对象时,
useffect
会连续运行。这是因为React使用引用相等(而不是深度相等)来检查内容是否已更改

我可以通过在
usemo
中包装我的配置来“修复”这个问题,或者将其移到渲染方法之外。这两种情况对开发人员的体验都非常不利

我尝试了Kent C.Dodds的库,但由于我在配置中允许内联箭头函数,所以它“不起作用”

最好,我希望能够让用户输入一个内联对象,并让我以某种方式处理任何更改


如何解决这个问题?

看起来这是代码中唯一的语法错误

您的函数应该如下所示

function useValidation(config) {
 const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields, state])
}

看起来这是代码中唯一的语法错误

您的函数应该如下所示

function useValidation(config) {
 const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields, state])
}

在我看来,每次渲染都会调用
useffect
,因为每次传递给
useffect
的配置都是动态创建的。我的建议是将其置于组件中使用
useValidation
useValidation
本身的某个位置,如下所示:

function useValidation(config) {
  const [storedConfig, setStoredConfig] = useState(config);
  const [state, dispatch] = useReducer(validationReducer);

  useEffect(() => {
    validateFields(config.fields, state);
  }, [storedConfig.fields, state]);
}

如果配置是可更改的,那么您应该将其存储在钩子之外,无论哪种方式,都要确保配置不是每次渲染时都是一个新对象。

在我看来,
useffect
在每次渲染时都被调用,因为您传递给
usevalization
的配置每次都是动态创建的。我的建议是将其置于组件中使用
useValidation
useValidation
本身的某个位置,如下所示:

function useValidation(config) {
  const [storedConfig, setStoredConfig] = useState(config);
  const [state, dispatch] = useReducer(validationReducer);

  useEffect(() => {
    validateFields(config.fields, state);
  }, [storedConfig.fields, state]);
}

如果配置是可更改的,那么您应该将其存储在钩子之外,无论哪种方式,都要确保配置不是每次渲染时都是一个新对象。

根据文档,您不应该将对象或数组放在数组上,而应该将各个属性放在其中,如下所示:

function useValidation(config) {
  const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields.username, state]);
}
我不知道你的
状态是什么,但是应该是一个不可变的值,比如字符串、数字、布尔值等等


Date
对象相同,它们应该首先被强制转换为
String

根据文档,不应该将对象或数组放在数组上,而应该将单个属性放在数组中,如下所示:

function useValidation(config) {
  const [state, dispatch] = useReducer(validationReducer);
  useEffect(() => {
    validateFields(config.fields, state);
  }, [config.fields.username, state]);
}
我不知道你的
状态是什么,但是应该是一个不可变的值,比如字符串、数字、布尔值等等


对于
Date
对象也一样,它们应该首先被转换为
String

谢谢提示-修复了我的示例代码。不幸的是,这个问题仍然存在。感谢您的提示-修复了我的示例代码。不幸的是,问题仍然存在。感谢您的解释。我同意,我的问题更多的是关于我可以做些什么来跳过在钩子之外保存配置。«Outiside»钩子意味着它将留给我的钩子的消费者——我正试图简化开发人员的体验。感谢您的解释。我同意,我的问题更多的是关于我可以做些什么来跳过在钩子之外保存配置。«Outiside»钩子意味着它将留给我的钩子的消费者——我正试图简化开发人员的体验。