需要更清晰的解释如何避免使用 React 钩子进行无限重新渲染 [英] Need a clearer explanation how to avoid infinite re-rendering with React hooks

查看:73
本文介绍了需要更清晰的解释如何避免使用 React 钩子进行无限重新渲染的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对 React hooks 不太熟练,之前用过很多类组件,希望你能原谅.

当前代码导致无限重新渲染,我想我明白为什么 - 整个函数体在重新渲染时被调用.

const NavTabs = () =>{const 类 = useStyles();const [categories, setCategories] = React.useState();const axiosPromise = getRequest(consts.categoriesURL);axiosPromise.then(data => {setCategories(data.value);})返回 (<div className={classes.root}><AppBar position="static"></AppBar>{类别&&<DynamicTabs 类别={类别}/>}

);}

我想我可以做类似 if (!categories) { const axiosPromise [...] 之类的事情,即只有在类别尚未填充时才执行 http 请求.我想这也可以通过 useEffect 解决?还是将钩子包装在内部函数中?

我想我真正的问题是 - 为什么 React 会重新渲染整个函数体?它不应该只重新渲染返回函数吗?那么使用每次渲染都会重新运行的钩子有什么意义呢?

相对于类组件——函数体中的代码不应该等同于类组件中的构造函数代码,而返回函数——等同于render方法吗?

解决方案

是的,每个渲染周期都会调用 getRequest 来设置一些状态并触发重新渲染.将它放在一个带有依赖数组的效果钩子中可能是最好的解决方案.您定义的依赖项将决定何时可以调用 getRequest.

<块引用>

为什么 React 会重新渲染整个函数体?

整个函数体需要运行才能确定返回值.

<块引用>

那么使用每次渲染都会重新运行的钩子有什么意义?

钩子在每个渲染上运行,它们的定义顺序相同,但根据依赖关系可能不会调用回调.钩子赋予了功能组件如此多的生命周期和生命周期感,在功能上几乎等同于基于类的组件.在大多数情况下,您可以将基于类的组件完全转换为功能性组件,而不会删除任何功能.

<块引用>

相对于类组件——函数体中的代码不应该等同于类组件中的构造函数代码,而返回函数——等同于render方法吗?

将整个功能组件定义视为基于类的render函数更准确,它可以 包含一些逻辑并返回计算出的 JSX 以呈现给 DOM.

示例解决方案:

const NavTabs = () =>{const 类 = useStyles();const [categories, setCategories] = React.useState();//<-- 没有初始状态!useEffect(() => {getRequest(consts.categoriesURL).then(data => {setCategories(data.value);//<-- 将更新状态并触发渲染});}, []);//<-- 空依赖在组件挂载时运行一次返回 (<div className={classes.root}><AppBar position="static"></AppBar>{类别&&<DynamicTabs 类别={类别}/>}

);}

Not so fluent with React hooks, used plenty of class components before, hope you'll be forgiving.

The current code causes infinite re-rendering, and I think I understand why - the entire function body is being called on re-render.

const NavTabs = () => {
  const classes = useStyles();

  const [categories, setCategories] = React.useState();
  const axiosPromise = getRequest(consts.categoriesURL);

  axiosPromise.then(data => {
    setCategories(data.value);
  })

  return (
    <div className={classes.root}>
      <AppBar position="static">
      </AppBar>
      {categories && <DynamicTabs categories={categories}/>}
    </div>
  );
}

I guess I could do something like if (!categories) { const axiosPromise [...] and so forth, i.e. do the http request only if categories haven't been populated yet. I guess this could also be solved by useEffect? Or wrapping the hook in an internal function?

I guess my real question is - why is React re-rendering the entire function body? Shouldn't it re-render only the return function? And then what is the point of using hooks that will be re-run on every render?

Compared to class components - shouldn't the code in the function body be equivalent to the constructor code in class components, and the return function - equivalent to the render method?

解决方案

Yes, getRequest is being invoked each render cycle which sets some state and triggers a rerender. Placing it in an effect hook with a dependency array is likely the best solution. What dependencies you define will dictate when getRequest can be invoked.

Why is React re-rendering the entire function body?

The entire function body needs to run in order to determine the return value.

And then what is the point of using hooks that will be re-run on every render?

Hooks are run on every render, in the same order they are defined, but depending on dependencies may not invoke a callback. Hooks are what give functional components so much viability and sense of component lifecycle, to nearly be equivalent to class-based components in functionality. In most cases, you can completely convert a class-based component to a functional one and not drop any functionality.

Compared to class components - shouldn't the code in the function body be equivalent to the constructor code in class components, and the return function - equivalent to the render method?

It is more accurate to think of the entire functional components definition as the class-based render function, which can contain some logic and returns computed JSX to render to the DOM.

Example Solution:

const NavTabs = () => {
  const classes = useStyles();

  const [categories, setCategories] = React.useState(); // <-- no initial state!

  useEffect(() => {
    getRequest(consts.categoriesURL).then(data => {
      setCategories(data.value); // <-- will update state and trigger render
    });
  }, []); // <-- empty dependency is run once on component mount

  return (
    <div className={classes.root}>
      <AppBar position="static">
      </AppBar>
      {categories && <DynamicTabs categories={categories}/>}
    </div>
  );
}

这篇关于需要更清晰的解释如何避免使用 React 钩子进行无限重新渲染的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆