React 百思不得其解的重复渲染问题

发布于 2022-09-12 00:24:57 字数 7466 浏览 22 评论 0

最近在用React+React-Router4+Redux做一个后台系统,功能、页面啥的做得差不多了。然后想着做一些优化的工作,特别我发现很多重复渲染的问题让我很疑惑
比如:
有一个父组件MonitorHome,包含了两个ControlAiAlarm子组件,这两个子组件是一个组件。在父组件里dispatch了三个异步action,然后在ControlAiAlarm里面dispatch了两个异步action去获请求接口。然后就发现子组件总共执行了十次render方法,甚至十几次,实在没想明白为什么重复渲染了这么次,不知道该怎么优化
父组件MonitorHome:

class MonitorHome extends Component { 
    constructor(props) {
        super(props)
        this.timer = null
    }
    componentDidMount() {
        const { getDataByMonth, getDataByStation, getAiListData } = this.props;
        getDataByMonth({ m: 3, t: 1 });
        getDataByStation({m: 30, n: 2, t: 1});
        getAiListData(60);
        this.timer = setTimeout(() => {
            getAiListData(60);
        }, 60000);
    }
    componentWillUnmount() {
        clearInterval(this.timer)
    }
    render() {    
        return (
            <div className='monitorHome-container'>
               <Row>
                   <Col span={8}>
                       <ControlAiAlarm name='control' title='近半年控制器报警归类统计'/>
                   </Col>
                   <Col span={8}>                     
                        <ControlAiAlarm name='ai' title='近半年AI报警归类统计' />
                   </Col>
                   <Col span={8}>
                        <AlarmTimeDiff {...this.props} />         
                    </Col>
               </Row>
                <Row>
                    <Col span={11}>
                        <StationAlarmDiff {...this.props} />
                    </Col>
                    <Col span={13}>
                        <RealTimeAlarm {...this.props} />
                    </Col>
                </Row>
            </div>
        )
    }
}

const mapStateToProps =  state => {
    const { controllerData, aiModelData, aiListData,byMonthData, byStationData } =  state.alarmDataReducer
    return {
        controllerData,
        aiModelData,
        aiListData,
        byMonthData,
        byStationData
    }
}
const mapDispatchToProps = dispatch => ({
    getDataByMonth(params) {
        dispatch(fetchByMonthAction(params))
    },
    getDataByStation(params) {
        dispatch(fetchByStationAction(params))
    },
    getAiListData(n) {
        dispatch(fetchAiDataListAction(n))
    }
})
export default connect(mapStateToProps,mapDispatchToProps)(MonitorHome)

子组件ControlAiAlarm:

class ControlAiAlarm extends Component {
    constructor(props) {
        super(props)
        this.state = {
            controllerData: [],
            aiModelData: [],
        }
    }
    componentDidMount() {
        const { getControllerData, getAiModelData} = this.props;
        let params = { m: 6, n: 10}
        getControllerData(params);
        getAiModelData(params);
    }
    static getDerivedStateFromProps(nextProps, prevState) {
        const { controllerData, aiModelData } = nextProps;
        if(controllerData !== prevState.controllerData) return { controllerData };
        if(aiModelData !== prevState.aiModelData) return { aiModelData };
        return null;
    }
    getOption () {
        const { controllerData, aiModelData } = this.state;
        const { theStaAiData = false, name } = this.props;
        const { serie: controlSeries } = controllerData;
        const { serie: aiSeries } = theStaAiData || aiModelData
        let arr = (name === 'control' && controlSeries) || aiSeries
        // * 计算最大报警次数及其占比
        let maxVal = toolUtil.getArrObjMax(arr);
        let sumVal = toolUtil.getArrObjSum(arr);
        arr && arr.length && arr.forEach( item => {
            if(item.value === maxVal) Object.assign(item, {
                label: {
                    show: true
                },
                labelLine: {
                    show: true
                }
            })
        })
        let perVal = maxVal && sumVal && ((maxVal / sumVal * 100).toFixed(2) + '%');

        let option = {
            title: {
                text: `${maxVal}次`,
                left: 'center',
                top: '35%',
                subtext: perVal,
                textStyle: {
                    fontSize: 22,
                    color: '#FFFFFF'
                },
                subtextStyle: {
                    fontSize: 16,
                    color: '#FFFFFF',
                    fontFamily: 'Adobe Heiti Std',
                }
            },
            tooltip: {
                trigger: 'item',
                formatter: "{a} <br/>{b} : {c} ({d}%)"
            },
            series: [
                {
                    name: '报警参数',
                    type: 'pie',
                    radius: ['50%', '80%'],
                    center: [
                        '50%', '50%'
                    ],
                    label: {
                        normal: {// 文字长度超过3个时,换行显示
                            show: false,
                            color: '#fff',
                            formatter(v) {
                                let text = v.name
                                return text.length < 3 ? text : `${text.slice(0,3)} \n${text.slice(3)}`
                            }
                        },
                    },
                    labelLine: {
                        normal: {
                            show: false
                        }
                    },
                    data: arr,
                    color: ['#4bb0f4', '#f25ca2', '#f5af19', '#91eae4', '#eef5b2', '#0ce19e','#1b55e3', ],
                    itemStyle: {
                        emphasis: {
                            shadowBlur: 10,
                            shadowOffsetX: 0,
                            shadowColor: 'rgba(0, 0, 0, 0.5)'
                        }
                    }
                }
            ]
        }
        return option;
    }
    render() {
        console.log('看看子组件的渲染次数') // 输出了十几次
        return (
            <Fragment>
               <div className='title title-1'>
                    <img src='/assets/images/circle-icon.png' alt='' />
                    <span>{this.props.title}</span>
                </div>
                <div className='detail detail-1'>
                    <div className='subTitle'>
                        <img src='/assets/images/alarm-1.png' alt='' />
                        <span>报警参数 top10</span>
                    </div>
                    <ReactEcharts
                        option={this.getOption()}
                        notMerge={true}
                        lazyUpdate={true}
                        style={{width: 394,height: 206}}
                    />
                </div>
            </Fragment>          
        )
    }
}

const mapStateToProps =  state => {
    const { controllerData, aiModelData } =  state.alarmDataReducer
    return {
        controllerData,
        aiModelData,
    }
}
const mapDispatchToProps = dispatch => ({
    getControllerData(params) {
        dispatch(fetcControllerDataAction(params))
    },
    getAiModelData(params) {
        dispatch(fetchAiModelDataAction(params))
    }
})
export default connect(mapStateToProps,mapDispatchToProps)(ControlAiAlarm)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

潜移默化 2022-09-19 00:24:57

没细看,但是优化第一条:把Component改成PureComponent就对了

任性一次 2022-09-19 00:24:57

React里引起组件变化的一般不是state和Props改变之后

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文