在反应中使用嵌套的api调用来执行setState闪烁

时间:2018-02-22 03:37:04

标签: javascript reactjs

我想加载一堆涉及多个API的数据,我在foreach中做了setState,它工作但我认为设计是错误的,因为我看到我的屏幕上闪烁。

API.fetchMain().then(main => {
  main.forEach(o => {
    const main_id = o.main_id

    this.setState({
      main: o
    })

      API.fetchSub(main_id)
      .then(sub => {

        this.setState({
          sub
        })

        API.fetchOthers(main_id, sub.id)
        .then(others => {
          this.setState({
            others
          })
        })

      })
  })
}

我认为我应该使用promises来重构,我试过但我认为我的设计是错误的。

API.fetchMain().then(main => {

  let promise = []

  main.forEach(o => {
    const main_id = o.main_id

    this.setState({
      main: o
    })

    promise.push(
      API.fetchSub(main_id)
      .then(sub => {

        return API.fetchOthers(main_id, sub.id)

      })
    )
  })

  Promise.all(promise).then(resp => console.log('do setState here'))

}

需要帮助。

1 个答案:

答案 0 :(得分:0)

在我看来,您正在获取一个资源,该资源为您提供有关如何进一步请求的信息。如果您愿意使用获取库,我建议axios。下面是我想象它的样子

import axios from 'axios'

fetch(){
  // Make the initial request
  var options = { url: "URL of main resource", method: "GET" }
  axios(options).then(res => {
    // Create an array of next requests from the response
    var next_requests = res.data.main.map(id => axios.get(`${resource_url}/${id}`))

    //Make the requests in parallel
    axios.all(next_requests).then(axios.spread(() => {
       //since we don't know how many request we can iterate 
       //over the arguments object and build the new state
       var newState = {}
       arguments.forEach(i => {
         // how you want to structure the the state before setting it
       })
       this.setState(newState)    
    })

  }).catch(err => //error handling logic here)
}

根据我对你的问题的理解,你也可以(因为你正在使用react)将你的获取请求分解为在挂载时被调用的组件。一个简单的例子:

const class MainComp extends Component {
  constructor(props){
    super(props)
    this.state = {
      main: []
    }
  }
  componentDidMount(){ this.fetchMain() }

  fetchMain() { 
     axios.get('url').then(res => 
        this.setState({main_id: res.data.main.id})
  }

  sendSubFetchToParent(dataFromChild){
     // Do what you need to with the data from the SubComp child
  }

  render(){
     return (
        {this.state.main.map(id => <SubComp id={id) afterFetch={this.sendSubFetchToParent}/>}
     )
  }
}

const class SubComp extends Component {

  componentDidMount(){ this.fetchSub() }

  fetchSub() { 
     //Pass the results to the parent after the fetch completes.
     // You can add the usual error handling here as well.
     axios.get('url').then(res => this.props.afterFetch(res.data))
  }

  render(){
     //Return null or render another sub component for further nested requests
     return null
  }
}

在上面,MainComp发起请求。当它得到一个响应(在你的例子中是一个数组)时,我们将该响应设置为状态。这会触发重新渲染,它将安装n个SubComp。当这些安装时,他们将发起他们获取数据的请求。对于SubComp,我们从父级传递回调,因此SubComp可以将其获取响应发送回MainComp(并通过设置状态等来适当地处理它)。您可以在SubComp中返回null,或者让它挂载将进一步请求的组件。

通过这种方式,您的获取请求现在已组件化。