Javascript 如何使用React中的useEffect()防止无限重渲染

Javascript 如何使用React中的useEffect()防止无限重渲染,javascript,reactjs,react-hooks,use-effect,Javascript,Reactjs,React Hooks,Use Effect,我有一个应用程序,可以在启动时检查用户id,并根据登录的用户加载待办事项列表。只有当数据发生变化时,我的useEffect才会发生变化,但在useEffect()的主体中,我有设置数据,意思是数据发生变化,它会重新无限运行 但是,如果我在第二个参数中将[data]更改为[],则它会呈现一次,但每次我添加todo项时,我都必须刷新页面,以便它呈现,而不是自动呈现。如何让它自动渲染而不无限循环 const [data, setData] = useState([]) useEffect(() =&

我有一个应用程序,可以在启动时检查用户id,并根据登录的用户加载待办事项列表。只有当
数据
发生变化时,我的useEffect才会发生变化,但在useEffect()的主体中,我有
设置数据
,意思是
数据
发生变化,它会重新无限运行

但是,如果我在第二个参数中将
[data]
更改为
[]
,则它会呈现一次,但每次我添加todo项时,我都必须刷新页面,以便它呈现,而不是自动呈现。如何让它自动渲染而不无限循环

const [data, setData] = useState([])

useEffect(() => {
    UserService.getUserById(localStorage.getItem("userId")).then(res => {
        if (res.data !== null) {
            setData(res.data.todos)
        }
    })
}, [data])

useCallback
Hook可以在代码中稍加修改后使用

您需要首先从“react”导入useCallback

然后围绕我们的
getData
函数使用这个
useCallback
。(对答案稍加修改)


此React钩子将确保仅当第二个参数
data
更改时才创建
getData()
函数。

在您的代码中
UserService.getUserById(localStorage.getItem(“userId”))
返回一个承诺,它只会获取一次数据,因此您只需在加载时使用
[]
调用一次
getUserById
,如果您想再次调用它,则在刷新函数或添加todos项或更新或删除函数时创建一个函数并在任何位置使用它。否则,您必须使用可观察的或使用回调挂钩

您需要传递重置参数以防止循环。一旦回调触发重置值为false。因此,在重置该值之前,执行不会再次运行

  export default function App() {
  let i = 1;
  const [data, setData] = useState([]);
  const [reset, setReset] = useState(true);

  useEffect(() => {
    if (reset) {
      setTimeout(() => {
        //callback
        setReset(false);
        setData(Math.random());
      }, 1000);
    }
  }, [data]);

  return (
    <div className="App">
      <h1>{data}</h1>
      <button
        onClick={() => {
          setReset(true);
          setData("");
        }}
      >
        Click this and see the data render again. i just reset the data to empty
      </button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}
导出默认函数App(){
设i=1;
const[data,setData]=useState([]);
const[reset,setReset]=useState(true);
useffect(()=>{
如果(重置){
设置超时(()=>{
//回拨
设置重置(假);
setData(Math.random());
}, 1000);
}
},[数据];
返回(
{data}
{
设置重置(真);
setData(“”);
}}
>
单击此按钮并再次查看数据渲染。我只是将数据重置为空
开始编辑,看看神奇的发生!
);
}

您可以在回调函数中添加一个条件,用于检查是否满足某个条件,例如数据是否为空。如果为空,则获取数据,否则不执行任何操作。这将防止无限循环发生


const getData=useffect(()=>{
常量fetchData=()=>{
UserService.getUserById(localStorage.getItem(“userId”))
。然后(res=>{
if(res.data!==null){
setData(res.data.todos)
}
})
.catch(错误=>{
//做错事
})
}
如果(data.length==0)
fetchData()
},[数据];

或者,您可以使用一个空的依赖项数组,以便调用useEffect中的回调函数一次。

通过设置停止循环的条件,使用条件停止循环。您可以检查是否设置了某个值或是否发送了任何值。

需要显示更多代码。@Jakkie Chan为了避免无限循环,您可以检查以前的数据(如计数),然后可以setData@buzatto不,我没有传入和比较任何对象。依赖项数组中的
数据是什么?它似乎不是效果的依赖项。这相当于在第二个参数中使用
[]
,它仅在刷新时渲染,而不是自动渲染。您还调用了
setData
来更新它吗?如果您没有在代码中的其他位置调用setData,则组件将不会“自动”重新渲染。如果这是您调用它的唯一位置,则
数据
将永远不会更新,因此组件将永远不会重新渲染,因为组件的状态变量从未更改。你是如何添加待办事项的?我刚试过,但它仍然呈现无限的效果,嗯,我明白了。您在问题中提到,
每次添加todo项时,我都必须刷新页面,以使其呈现,而不是自动呈现。我认为这就是我们需要改进代码的地方。在这里,您实际上需要在单击add item
按钮时放置处理程序函数。如果您可以通过codesandbox向我展示您的代码,我想看看问题到底出在哪里:-)暂时也不要使用
localStorage
,您可以简单地将所有数据存储在一个对象数组中以供演示之用:-)
const getData =  useCallback(()=>{
    UserService.getUserById(localStorage.getItem("userId")).then(res => {
        if (res.data !== null) {
            setData(res.data.todos)
        }
    })
},[data]);


useEffect(() => {
   getData();
}, [data])
  export default function App() {
  let i = 1;
  const [data, setData] = useState([]);
  const [reset, setReset] = useState(true);

  useEffect(() => {
    if (reset) {
      setTimeout(() => {
        //callback
        setReset(false);
        setData(Math.random());
      }, 1000);
    }
  }, [data]);

  return (
    <div className="App">
      <h1>{data}</h1>
      <button
        onClick={() => {
          setReset(true);
          setData("");
        }}
      >
        Click this and see the data render again. i just reset the data to empty
      </button>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}