Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/21.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript React.js:useffect()依赖项冻结我的应用程序_Javascript_Reactjs_React Hooks_Use Effect - Fatal编程技术网

Javascript React.js:useffect()依赖项冻结我的应用程序

Javascript React.js:useffect()依赖项冻结我的应用程序,javascript,reactjs,react-hooks,use-effect,Javascript,Reactjs,React Hooks,Use Effect,我试图在用户以前未选择任何产品时显示模式。我最终得到了一个无限的useffect()依赖循环。我不知道如何正确地做这件事 import React, { useState, useEffect, useCallback } from 'react'; const MyComponent = ({ products }) => { const [modals, setModals] = useState({}); const [currentModalName, setCu

我试图在用户以前未选择任何产品时显示模式。我最终得到了一个无限的
useffect()
依赖循环。我不知道如何正确地做这件事

import React, { useState, useEffect, useCallback } from 'react';

const MyComponent = ({ products }) => {
    const [modals, setModals] = useState({});
    const [currentModalName, setCurrentModalName] = useState('');

    const setCurrentModal = useCallback(
        (modalName, data = {}) => {
            if (modalName) {
                setModals({
                    ...modals,
                    [modalName]: {
                        ...modals[modalName],
                        ...data
                    }
                });
            }

            setCurrentModalName(modalName);
        },
        [modals]
    );

    useEffect(
        () => {
            if (!products.length) {
                setCurrentModal('chooseProduct')
            }
        },
        [products, setCurrentModal] // setCurrentModal causes infinite loop
    );

    return (
        <div>...</div>
    );
}

export default MyComponent;
import React,{useState,useffect,useCallback}来自'React';
常量MyComponent=({products})=>{
const[modals,setModals]=useState({});
常量[currentModalName,setCurrentModalName]=useState(“”);
const setCurrentModal=useCallback(
(modalName,data={})=>{
if(modalName){
设置模态({
…情态动词,
[modalName]:{
…模态[模态名称],
…数据
}
});
}
setCurrentModalName(modalName);
},
[情态动词]
);
使用效果(
() => {
如果(!products.length){
setCurrentModal('chooseProduct')
}
},
[产品,setCurrentModal]//setCurrentModal导致无限循环
);
返回(
...
);
}
导出默认MyComponent;
我可以从依赖项中删除
setcurrentmodel
,但是我收到了警告。如果我添加它,我的React应用程序将冻结

如何组织代码以避免冻结?

为什么会循环? 回调总是在变化,因为它依赖于
modals
,而modals始终是一个不同的对象,即使它具有与以前完全相同的属性,它总是触发
useffect
,因为它依赖于
setCurrentModal
回调值,而回调值总是不同的,因为
(()=>{})!==(()=>{})

解决方案 需要当前状态时始终使用设置下一个状态

它将防止将
modals
状态作为依赖项使用,这将限制回调的更新时间,同时修复无限循环

除了解决今天的问题外,状态的功能更新不太容易出现争用情况,React批处理的多个更新会相互覆盖

const setCurrentModal = useCallback(
  (modalName, data = {}) => {
    if (!modalName) return; // precondition fail? early return.

    // Happy path here!

    // Note that I've used a different name to highlight that 
    // it's a different variable and to avoid shadowing the 
    // `modals` var from the outer scope.
    setModals((currentModals) => ({ // use functional update. 
      ...currentModals,
      [modalName]: {
        ...currentModals[modalName],
        ...data
      }
    }));

    setCurrentModalName(modalName);
  }, 
  // remove `modals` from the dependencies.
  // setter functions are stable anyway, so it should remove any warning.
  [setModals, setCurrentModalName]
);

useEffect(() => {
    if (!products.length) {
      setCurrentModal('chooseProduct')
    }
  },
  [products, setCurrentModal] 
);
由于
setCurrentModal
回调现在是稳定的(从未更改),因此只有当
products
值更改时才会调用
useffect

缺少依赖项警告 缺少依赖项警告来自
react hooks/deps
规则。它是完全可选的,但它有助于保持代码干净和安全

您还可以选择仅针对此行禁用警告:

const setCurrentModal = useCallback(
  (modalName, data = {}) => {
    // ...
    setModals(/* ... */);
    setCurrentModalName(modalName);
  }, 
  [] // eslint-disable-line react-hooks/exhaustive-deps
);

我认为您可以简化它,而无需使用useCallback

(使用Next.js进行测试,没有警告,但如果仍然有警告,则应使用@Emile Bergeron的答案)


相关:但是我在我的组件中使用这种更改模态的逻辑。只是用外部化函数编辑了代码警告仍然存在。是的,只是用useCallback编辑了帖子以防止警告问题是,在这种情况下,我仍然被警告缺少
setCurrentModal
依赖项。我认为这是因为它位于功能组件内部,所以即使它是
常量
,它仍将在下一个周期中更改。我可以将
setcurrentmodel
移动到组件外部,除了is使用状态。@RoboRobok我已经用所有相关的依赖项更新了我的答案,这些依赖项将删除任何警告并修复循环问题。它说
modals
也是必需的依赖项,不幸的是。@RoboRobok这意味着
modals
仍在回调或效果中使用,并且您没有正确实现我的答案中的内容(这将从回调中完全删除
modals
状态)。非常感谢!很抱歉,一开始我忽略了你答案的某些部分,我感到不知所措。谢谢你的回答。
import React, { useState, useEffect } from 'react'

const MyComponent = ({ products }) => {
  const [modals, setModals] = useState({})
  const [currentModalName, setCurrentModalName] = useState('')

  const setCurrentModal = (name, data) => {
    if (name) {
      setModals(prev => {
        return { ...prev, [name]: { ...prev[name], ...data }}
      })
      setCurrentModalName(name)
    }
  }

  useEffect(() => {
    if (!products || !products.length) {
      const modalName = 'chooseProduct'
      const data = { data: 'data' }

      setCurrentModal(modalName, data)
    }
  }, [products])

  const modalsJsx = modals ? Object.keys(modals).map((x, i) => {
    return <li key={`modal-${i}`}>{x}</li>
  }) : ''

  const addModal = () => {
    const name = 'test' + Math.floor(Math.random() * Math.floor(300))
    setCurrentModal(name, { data: 'Hey' })
  }

  return (
    <div>
      <p>Current Modal : {currentModalName}</p>
      <p>Modals : </p>
      <ul>
        {modalsJsx}
      </ul>

      <button onClick={addModal}>Test</button>
    </div>
  )
}

export default MyComponent
  const setCurrentModal = useCallback((name, data = {}) => {
    if (name) {
      setModals(prev => {
        return { ...prev, [name]: { ...prev[name], ...data }}
      })
      setCurrentModalName(name)
    }
  }, [setModals, setCurrentModalName])