【问题标题】:ReactJS: multiple setStates happening asynchronously, state not updatedReactJS:多个 setStates 异步发生,状态未更新
【发布时间】:2019-03-18 15:40:46
【问题描述】:

在触发位于渲染中的函数 (filterAndSort) 之前,面临状态未更新的问题。我在函数中添加了一个 console.log 语句,并且只有一个状态得到更新。我的代码对我来说似乎是合乎逻辑的,因为我设置了一个 if 条件,其中只有在 setState 发生后才会触发函数

完整的错误信息:

警告:无法在未安装的设备上调用 setState(或 forceUpdate) 零件。这是一个无操作,但它表明您的内存泄漏 应用。要修复,请取消所有订阅和异步任务 在 componentWillUnmount 方法中。

但是,我怀疑这是因为我有多个 setStates 异步发生。

我在想,也许,只有在获取所有 axios 请求后,我才需要为所有变量重写 componendDidMount 到 setState。 Multiple Axios Requests Into ReactJS State

我认为另一种解决方案是将函数的返回结果存储为状态而不是变量,然后添加 componentDidUpdate。

componentDidUpdate(prevProps, prevState) {
  if (this.state.value > prevState.value) {
    this.filterAndSort();  
  }
}

组件

class Results extends Component {

  constructor(){
    super()
    this.state = {
      results: [],
      races: [],
      arr = []
      isLoading: true
    };
  }

  componentDidMount(){

    const oneRequest = axios.get(URL_ONE)
                              .then(response =>
                                    response.data.data.map(result => ({...
                                    ))
                                    )
                              .then(results => this.setState({results, isLoading: false}))    

    const twoRequest = axios.get(URL_TWO)
                              .then(response =>
                                response.data.data.map(race => ({...}))
                                )
                          .then(races => this.setDefault(races))

  }

   setDefault = (races) => {
    ........
    this.setState({arr, races, isLoading:false})
  }

  filterAndSort = (races, results) => {
    console.log(races, results)
    .......
  }

  render() {

    const{races, results} = this.state

      if (isLoading == true) {
        return (
          <div>
            <p>Loading...</p>   
          </div>
        )
      } else {
        return (
          <div>
            <BarChart 
              qualData={this.filterAndSort(races, results)} 
              raceData={this.filterAndSort(races, results)} 
              width="1200" 
              height="500" />

          </div>
          );
        }
      }

}

export default Results;

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    嗯,我想到了很多事情。

    首先,只有当你有两条数据之一时才将 isLoading 设置为 false,以先到者为准,因此渲染方法将在某些时候调用你的函数,要么是空的比赛,要么是结果。 另一件事,您正在异步调用 setState。到请求完成时,您的组件可能不再存在,因此它将尝试更新不存在的组件并因该错误而失败。

    对于第一个问题,一种可能的解决方案是为结果和比赛设置两个 isLoading 变量。

    对于第二个问题(在 unmountedComponent 上调用 setState),它有点复杂,因为您需要以某种方式取消请求。我建议阅读更多关于此的内容,一般建议是使用 redux 之类的库将数据从组件中移出。如果你用谷歌搜索cancel promise on unmount,你会发现关于这个的讨论。您也可以使用“isMounted”变量来处理它,这将作为一个丑陋的补丁。

    因此,一旦请求一(或二)完成,就会调用 setState,然后重新渲染组件。 isLoading 现在为真,因此 filterAndSort 被调用并带有结果(或竞赛),但不是两者都调用,因为第二个请求仍处于未决状态。

    最后,在您的渲染方法中,您的 isLoading 需要首先定义(我假设它在您的代码中是可以的,但不是在问题中),并且 is True 比较可以更好地作为

    if (isLoading) { 而不是if (isLoading == True) {

    【讨论】:

      【解决方案2】:

      你是对的。当提出多个请求时,最好的做法是等待它们全部解决后再继续。为此,您可以使用 ES6 中内置的 Promise 库。此外,据我所知,为了获取数据,它的最佳实践是在componentWillMount() 中进行。我还要补充一点,this 的上下文在异步函数中会发生变化。所以在你的componentWillMount():

      let promiseArr = [axios.get(URL_ONE), axios.get(URL_TWO)];
      let _this = this;
      Promise.all(promiseArr)
        .then((resp) => {
          // Call _this.setState() here. Response from URL_ONE  
          // will be available in resp.data[0] and URL_TWO in resp.data[1]
        }).catch((err) => {
          console.log(err);
        })
      

      另外,在你的构造函数中:

      constructor(){
          super()
          this.state = {
            results: [],
            races: [],
            arr = []
            isLoading: true
          };
          this.setDefault = this.setDefault.bind(this);
          this.filterAndSort = this.filterAndSort.bind(this);
      }
      

      使用.bind 确保this 的上下文在调用这些方法时引用类的当前实例。

      我认为在做完这些事情之后,错误就会消失。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-09
        • 2014-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-15
        相关资源
        最近更新 更多