如何避免在渲染方法中使用 setState?

Posted

技术标签:

【中文标题】如何避免在渲染方法中使用 setState?【英文标题】:How to avoid using setState in render method? 【发布时间】:2019-08-14 02:57:42 【问题描述】:

我正在使用react-apollo 通过<Query /><Mutation /> 获取数据。 因此,当我得到一些数据时,我想setState。我在渲染方法中获取数据。 像这样:

render() 
    return (
      <Query query=CAN_UPDATE_POST_QUERY variables= id: this.props.router.query.postId >
         payload => 

          if(payload.loading) 
            <div style=width: '98%', textAlign: 'center', maxWidth: '1000px', margin: '50px auto'>Loading...</div>
          

          if(this.isNew())
            return (
              <PleaseSignIn>
                 me => (
                  ...something
                ) 
              </PleaseSignIn>
            )
           else if (payload.data && payload.data.canUpdatePost) 

            // I get payload here. Here's where I want to set new state.
            this.canUpdatePost = payload.data.canUpdatePost
            this.setState( canUpdatePost: this.canUpdatePost )


            return (
              <PleaseSignIn>
                 me => (
                  ...something
                ) 
              </PleaseSignIn>
            )


           else 
            return (
              <div style=width: '98%', textAlign: 'center', maxWidth: '1000px', margin: '50px auto'>You and your mind seems to be lost. ????</div>
            )
          

         
      </Query>
    )
  

在渲染中使用 setState 会给我这个错误: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

我如何以 React 方式思考?特别是,当我从react-apollo 获取有效负载时,如何更改我的状态?

这里是新手。对不起,如果愚蠢。

提前致谢。 :-)

【问题讨论】:

Setting state in the Query component of react-apollo的可能重复 组件可能会随着每次状态更改而重新渲染,并在每次导致进一步渲染时更新状态。 你根本没有使用 canUpdatePost。 我正在使用 canUpdatePost,只是我已经删除了该代码。 您需要提供***.com/help/mcve,并且不要剥离相关部分。 【参考方案1】:

一般来说,您应该避免在渲染函数中使用 setState。您应该避免在渲染函数中产生副作用(例如设置状态),而应该调用其他组件函数来处理组件中的数据更改。

render() 函数应该是纯函数,即不修改组件状态,每次调用都返回相同的结果,不直接与浏览器交互。

请参阅 react 文档中的 render() 方法参考:https://reactjs.org/docs/react-component.html#render

您可以在渲染方法之外创建一个函数来解决此问题,如下所示:

YourComponent extends React.Component 

   handleCanUpdatePost = (canUpdatePos) => 
     this.setState( canUpdatePost )
   

   render() 
       // Your render logic here
       // Whenever you want to setState do so by
       // calling this.handleCanUpdatePost(payload.data.canUpdatePost)
   

您还应该在设置之前检查 state 的值是否会发生变化,以避免不必要的重新渲染:

handleCanUpdatePost = (canUpdatePos) => 
     this.setState((state) =>  
       if(canUpdatePos !== state.canUpdatePost) 
         return canUpdatePost: payload.data.canUpdatePost
        
     )
   

【讨论】:

今天不得不说,你是神❤️ 将 setState 调用从 render 方法移动到 render 方法调用的函数除了混淆 setState 调用之外没有任何作用。 render 方法仍在调用 setState,只是通过另一个函数。真正的解决方案是更改组件逻辑,使 setState 调用在其他生命周期方法中,如 componentDidMount 等

以上是关于如何避免在渲染方法中使用 setState?的主要内容,如果未能解决你的问题,请参考以下文章

如何在我的示例中正确使用 setState()?

渲染后如何根据另一个状态使用 setState 更新状态?

setState 更改状态但不重新渲染

如何只渲染一个 Widget setState

如何避免未使用的 setState 函数?可以在没有 setter 的情况下创建 React useState 吗?

调用 React Setstate 回调但延迟渲染