【问题标题】:Why does this component not update when you use setState in a constructor in an asynchronous call - ReactJS/ReactNative?为什么当您在异步调用的构造函数中使用 setState 时此组件不更新 - ReactJS/ReactNative?
【发布时间】:2020-08-15 11:22:59
【问题描述】:

** 已编辑/重新措辞 **

在对我的问题进行了一些很好的回答之后,我编辑了问题中的代码,以尽可能清楚地说明我不理解的内容。

我有一个 withErrorHandler 将用作许多单独组件的 hoc。

其中一个组件是 MyComponent。

withErrorHandler 的 componentWillMount 中的代码按预期工作,但由于它是一个废弃的方法,我必须将它移到某个地方。

位置 - ComponentDidMount 拦截器将无法拦截错误。

位置 - 构造函数 拦截器将拦截错误,但 withError 处理程序中的 Modal 不会显示给用户。

这里到底发生了什么?

import React from 'react';
import Modal from '../../components/UI/Modal/Modal';
import Aux from '../Aux/Aux';

const withErrorHandler = (WrappedComponent, axiosInstance) => {
    return class extends React.Component {
        constructor(props) {
            super(props);
            this.state= {
                error: null
            };
        }
        
        componentWillMount() {
            let { request, response} = axiosInstance.interceptors;
            this.requestInterceptor = request.use(req => {
                this.setState({error: null});
                return req;
            })
            this.responseInterceptor = response.use(resp => resp, error => {
                console.log("axiosInstance Intercepted Error\t",error)
                this.setState({error})
            })
        }

        componentWillUnmount() {
            let { request, response} = axiosInstance.interceptors;
            request.eject(this.requestInterceptor);
            response.eject(this.responseInterceptor);
        }

        errorConfirmedHandler = () => {
            this.setState({error: null})
        }

        render() {
            return <Aux>
                <Modal show={this.state.error} modalClosed={this.errorConfirmedHandler}>
                    {this.state.error ? this.state.error.message : null}
                </Modal>
                <WrappedComponent {...this.props} />
            </Aux>
        }
    }
}

export default withErrorHandler;
import React, { Component } from 'react';
import axiosInstance from '../../AxiosInstance';
import Spinner from '../../components/UI/Spinner/Spinner';
import withErrorHandler from '../../hoc/withErrorHandler/withErrorhandler';

class MyComponent extends Component {

    constructor(props) {
        super(props);
        this.state = {
            ingredients: null,
            error: false
        }
    }

    componentDidMount() {
        // Deliberately placed Error in 'ingredients.json' by removing n
        axiosInstance.get('ingredients.jso').then(response => {
            this.setState({
                ingredients: response.data
            })
        }).catch(error => {
            console.log(`Unable to load Ingredients\nError:\t${JSON.stringify(error, null, 2)}`)
            this.setState({ error: true})
        })
    }

    render() {
        return (
                this.state.ingredients ?
                    <p>show ingredients</p> :
                    this.state.error ? <p>Ingredients Can't be loaded</p> : <Spinner />
        );
    }
}

export default withErrorHandler(MyComponent, axiosInstance);

【问题讨论】:

  • 您只能在已安装或正在安装的组件上调用 setState,您可能调用它太快了(例如,回调在生命周期中很快触发)。使用componentDidMount()
  • 检查您对this 的引用是否没有丢失。用 this 绑定 Promise。

标签: javascript reactjs react-native constructor setstate


【解决方案1】:

您不应该在constructor 中执行任何副作用,它基本上应该用于初始化本地状态(和其他变量)或与内容绑定函数。

其次,在反应中,您应该谨慎使用以下方法,因为它们在服务器和客户端上都被调用。

  1. constructor
  2. componentwillmount(已弃用)
  3. getderivedstatefromprops

更好的方法是在componentDidMount 生命周期方法中进行状态更新。该方法会在组件的整个生命周期内触发一次。

class Component1 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      result: null,
    };
    this.fetchResult = this.fetchResult.bind(this)
  }

  componentDidMount() {
    this.fetchResult()
  }

  fetchResult () {
    axiosInstance
      .get(url)
      .then((result) => {
        console.log("result", result);
        this.setState({ result });
      })
      .catch((error) => {});
  }

  render() {
    return (
      <>
        <h1>SomeText</h1>
        <p>{this.state.result ? "Hey, I got the result" : "Waiting..."}</p>
      </>
    );
  }
}

【讨论】:

    【解决方案2】:

    axiosInstance.get(url)等网络调用放在componentDidMount()生命周期方法中,而不是在构造函数中。像这样:

    class Component1 extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          result: null,
        };
      }
      
      componentDidMount() {
        axiosInstance
          .get(url)
          .then((result) => {
            console.log("result", result);
            this.setState({ result });
          })
          .catch((error) => {});
      }
      ...
    }
    

    【讨论】:

      猜你喜欢
      • 2018-06-16
      • 1970-01-01
      • 1970-01-01
      • 2015-05-09
      • 2021-08-11
      • 2021-11-27
      • 2019-11-10
      • 2020-07-28
      相关资源
      最近更新 更多