【问题标题】:How do I stop a component rendering before data is fetched?如何在获取数据之前停止组件渲染?
【发布时间】:2017-10-19 08:33:42
【问题描述】:

目前在响应中,我必须调用 componentDidMount 生命周期方法中的函数,在该方法中调用操作创建者来获取数据。但是,该组件使用数据,具体取决于响应的速度确定数据是否存在。我怎样才能使组件在数据位于其中之前不呈现?

componentDidMount() {
    this.props.getTotalHours()
    this.props.getTrained()
  }

渲染函数:

render() {
    let hours = parseInt(_.map(this.props.hours, 'hours'));
    let trained = _.map(this.props.trained, 'trained');
    return (
      <div className="o-layout--center u-margin-top-large">
          <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
            <div style={{width: '80%', margin: '0 auto'}}>
              <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
            </div>
          </div>

Action Creator 将请求返回的值存储在应用程序状态:

 export function getTotalHours() {
   const url = `${ROOT_URL}dashboard/hours`
   const request = axios.get(url)
   return {
     type: FETCH_HOURS,
     payload: request
   }
 }

【问题讨论】:

  • 您可以只返回一个空的 div,它在未获取数据之前不会渲染任何内容,或者您​​可以添加默认值并使用初始数据渲染某些内容,例如 hours = 0,当您获取数据时,您可以更新将更新您的视图的状态。
  • 将 this.props.getTotalHours() 和 this.props.getTrained() 移动到 componentWillMount 并在映射之前检查应用程序状态。

标签: javascript reactjs redux react-redux


【解决方案1】:

使用thenawait 控制您的异步操作,并使用this.state 控制您的内容是否被加载。仅在 this.state.loaded === true 之后呈现您的内容

constructor(props) {
  super(props)
  this.state = {
    loaded: false
  }
}

async componentDidMount() {
    await this.props.getTotalHours()
    await this.props.getTrained()
    this.setState({loaded: true})
  }

content() {
  let hours = parseInt(_.map(this.props.hours, 'hours'));
  let trained = _.map(this.props.trained, 'trained');
  return (
    <div className="o-layout--center u-margin-top-large">
    <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
      <div style={{width: '80%', margin: '0 auto'}}>
        <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
      </div>
    </div>
  )
}

render() {
  return (
  <div>
    {this.state.loaded ? this.content() : null}
  </div>
  )
}

编辑:如果您关心 API 调用的性能,您可以与 Promise.all 并行运行它们。

async componentDidMount() {
   const hours = this.props.getTotalHours()
   const trained = this.props.getTrained()
   await Promise.all([hours, trained])
   this.setState({loaded: true})
 }

【讨论】:

  • 我已经尝试过了,它会返回正在获取的 2 条数据中的 1 条,另一条仍在呈现未定义的值,即使该值已被获取。
  • @MattEllis 您确定您尝试映射的数据结构看起来符合您的预期吗?
  • 当记录返回的内容时,小时数总是在第二次渲染之前返回为 NaN,当它变成整数时
  • @MattEllis 您也可以设置一个布尔值来控制它。无论在哪里相关,您都可以使用Number.isNaN 作为您的条件。
【解决方案2】:

在您的构造函数中,声明一个状态变量以跟踪数据是否已加载。例如:

constructor (props) {
  super(props)
  this.state = {
    dataLoaded: false
  }
}

然后在您的render 方法中,如果this.state.dataLoaded 为false,则返回null:

render () {
  const { dataLoaded } = this.state
  return (
    <div>
      {
        dataLoaded &&
        <YourComponent />
      }
    </div>
  )
}

在您用于获取数据的方法中,请确保在获取数据时调用this.setState({ dataLoaded: true })

【讨论】:

    【解决方案3】:

    你不能停止渲染,但你可以给渲染什么条件。

    示例

    render() {
        if(this.props.hours. length <= 0 || this.props.trained.length <= 0 ) {
          return (<div><span>Loading...</span></div>);
        } else {
          let hours = parseInt(_.map(this.props.hours, 'hours'));
          let trained = _.map(this.props.trained, 'trained');
          return (
            <div className="o-layout--center u-margin-top-large">
                <div className="o-layout__item u-width-1/2@medium u-width-1/4@large">
                  <div style={{width: '80%', margin: '0 auto'}}>
                    <PieChart data={hours} goal={100} label=' Training Hours Completed'/>
                  </div>
                </div>
          )
        }
    

    【讨论】:

    • 这里的缺点是,当没有 hourstrained 条目时,您的应用会一直显示“正在加载...”,就好像它正在挂起一样。
    猜你喜欢
    • 1970-01-01
    • 2019-12-31
    • 2020-12-21
    • 2018-02-19
    • 2019-02-08
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多