首页 > 解决方案 > 渲染 +-5000 个 React 组件的组合需要很长时间

问题描述

我有这个渲染

        render() {
        let rows = []

        if (this.state.loaded) {
         //this.props.totalWeeks is 5000
          for (let i = 1; i <= this.props.totalWeeks; i++) {
            rows.push(<CalendarFields key={i} weekId={i} weeksToRegisterDate={this.props.weeksToRegisterDate} currentWeek={this.props.currentWeek} description={this.getDescription(i)} rating={this.getRating(i)} />)
          }
          return <div className="fieldsContainer ">{rows}</div>
        } else {
          return <p>fetching data...</p>
        }


      }

并且在应用程序中显示所花费的时间是巨大的。大约 5-6 秒,所以屏幕是空的,我猜我可以在渲染 dom 时添加一个加载屏幕。但我不能以某种方式加速它吗?

有什么办法可以加快速度吗?它基本上是由 20px 高、20px 宽的小立方体组成,每个小立方体都传递了自定义道具

编辑:基本上已经使用生产版本解决了

EDIT2:不,它没有,这是一种错觉

EDIT3:整个原始代码

import React from 'react'
import CalendarFields from './CalendarFields'
import { getUserId } from '../services/userInfo.js'
import API from '../services/axiosObject.js';
import constants from '../constants.js'
import { CircularProgress } from '@material-ui/core';
import './CalendarGrid.css'

class CalendarGrid extends React.Component {

  constructor() {
    super()

    this.state = {
      fieldsInfo: [],
      loaded: false
    }

  }



  componentDidMount() {

    const userId = getUserId();

    API.get(constants.urlBackend + '/getUserFieldsInfo/' + userId).then(response => {
      this.setState({
        fieldsInfo: response.data,
        loaded: true
      }, () => {
        console.log(this.state.fieldsInfo)
      })

    })
  }




  getDescription(id) {
    var newArray = this.state.fieldsInfo.filter(function (el) {
      return el.week_number == id
    })
    return newArray[0].text;
  }

  getRating(id) {
    var newArray = this.state.fieldsInfo.filter(function (el) {
      return el.week_number == id
    })
    return newArray[0].rating;
  }


  render() {

    let rows = []

    if (this.state.loaded) {
      for (let i = 1; i <= this.props.totalWeeks; i++) {
        rows.push(<CalendarFields key={i} weekId={i} weeksToRegisterDate={this.props.weeksToRegisterDate} currentWeek={this.props.currentWeek} description={this.getDescription(i)} rating={this.getRating(i)} />)
      }
      return <div className="fieldsContainer ">{rows}</div>
    } else {
      return <div className="gridLoadingContainer"><CircularProgress color="primary" iconStyle={"width: 150, height:150"}/></div>
    }


  }
}

export default CalendarGrid;

这是我尝试实现组件

    import React from 'react'
import CalendarFields from './CalendarFields'
import { getUserId } from '../services/userInfo.js'
import API from '../services/axiosObject.js';
import constants from '../constants.js'
import { CircularProgress } from '@material-ui/core';
import { FixedSizeList as List } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";
import './CalendarGrid.css'

class CalendarGrid extends React.Component {

  constructor() {
    super()

    this.state = {
      fieldsInfo: [],
      loaded: false,
      rows: ""
    }

  }



  componentDidMount() {

    const userId = getUserId();

    API.get(constants.urlBackend + '/getUserFieldsInfo/' + userId).then(response => {
      this.setState({
        fieldsInfo: response.data,
        loaded: true
      }, () => {
        console.log(this.state.fieldsInfo)
      })

    })
  }




  getDescription(id) {
    var newArray = this.state.fieldsInfo.filter(function (el) {
      return el.week_number == id
    })
    return newArray[0].text;
  }

  getRating(id) {
    var newArray = this.state.fieldsInfo.filter(function (el) {
      return el.week_number == id
    })
    return newArray[0].rating;
  }

  componentDidUpdate(){
    if(this.loaded ){
      this.composer();
    }
  }
  composer(){
     var row = ({ index, style }) => {
      const { weeksToRegisterDate, currentWeek } = this.props;
      console.log("index")
      console.log(index)
      if(this.state.loaded){
        console.log(this.getDescription(index))
        return (
           <CalendarFields
             key={index}
             weekId={index}
             style={style}
             weeksToRegisterDate={weeksToRegisterDate}
             currentWeek={currentWeek}
             description={this.getDescription(index)}
             rating={ this.getRating(index)}

            />
         );
      }

    }
    this.setState({
      rows: row
    }, () => console.log(this.state.rows))
  }



  render() {

    let rows = []

    if (this.state.loaded) {
      const { totalWeeks, weeksToRegisterDate, currentWeek } = this.props;
      return (
        <div className="fieldsContainer ">

              <List
                className="List"
                height={1000}
                itemCount={totalWeeks}
                itemSize={300}
                width={1000}
              >
                {this.state.rows}
              </List>


        </div>
      );
    } else {
      return <div className="gridLoadingContainer"><CircularProgress color="primary" iconStyle={"width: 150, height:150"}/></div>
    }


  }
}

export default CalendarGrid;

并没有真正让它发挥作用。我试图这样做,因为它显然无法等待数据获取

标签: reactjs

解决方案


您可能想要使用窗口。

窗口化或列表虚拟化是一种仅将当前“窗口”中的可见部分渲染或写入到 DOM 的概念。

请参阅react-window以了解其可能的实现。


推荐阅读