RangePicker时间插件导致React项目出现页面卡死问题处理

DatePicker 组件卡死问题总结

问题描述

在 React 项目中使用 DatePicker 组件时,遇到了页面卡死的问题。组件的主要功能是使用 Ant Design 的 RangePicker 组件来选择日期范围,并将日期格式从格里高利历转换为 Moment.js 格式。

当用户在页面上交互 DatePicker 组件时,浏览器出现卡死现象,导致用户无法正常操作页面。

原因分析

经过调查和调试,发现问题主要集中在以下几个方面:

  1. 不必要的重渲染

    • 组件在每次 onChange 事件触发时,会更新 state,导致整个组件重新渲染。
    • componentWillReceiveProps 接收到数据不同后,触发组件重新渲染,使用不当会导致组件不必要的更新和重渲染。
  2. 状态同步问题

    • 直接在 handleDateChange 方法中更新 tempValue,会导致状态在短时间内频繁变化,增加了浏览器的负担。
    • 导致状态更新的冲突和性能问题。
解决方案

为了解决以上问题,我们采取了以下措施:

  1. componentWillReceiveProps
    componentWillReceiveProps 添加条件判断,防止无限循环。

  2. 引入 tempSelectedValue 作为中间状态:

    • handleDateChange 方法中使用 tempSelectedValue 来暂存用户的输入,减少直接更新 tempValue 带来的频繁重渲染。
    • 只有在必要时才更新 tempValue,确保状态变化的稳定性和一致性。
改进后的代码
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { DatePicker } from 'antd';
import moment from 'moment';
import _ from 'lodash';
import './style.less';

const { RangePicker } = DatePicker;

function transformGregorianToMoment(format) {
  return _.chain(format).replace('yyyy', 'YYYY').replace('dd', 'DD').value();
}

export default class DateInput extends Component {
  static propTypes = {
    size: PropTypes.string, // antd Input size
    format: PropTypes.string.isRequired, // gregorian format
    locale: PropTypes.object,
    style: PropTypes.object,
    value: PropTypes.array,
    onChange: PropTypes.func,
    disabledDate: PropTypes.func,
  };

  static defaultProps = {
    size: 'default',
    value: undefined,
    locale: {},
    style: {},
    onChange: _.noop,
  };

  constructor(props) {
    super(props);
    this.state = {
      tempValue: props.value,
      tempSelectedValue: props.value,
    };
  }

  componentWillReceiveProps(nextProps, prevState) {
    if (!_.isEqual(nextProps.value, prevState.tempValue)) {
      return {
        tempValue: nextProps.value,
        tempSelectedValue: nextProps.value,
      };
    }
    return null;
  }

  handleDateChange = (mDate) => {
    const { onChange } = this.props;
    this.setState({ tempValue: mDate });
    onChange(mDate);
  };

  render() {
    const {
      size, style, format, locale, disabledDate,
    } = this.props;
    const { tempValue, tempSelectedValue } = this.state;
    const momentFormat = transformGregorianToMoment(format);
    const [start = new Date(), end = new Date()] = tempSelectedValue || []

    return (
      <span
        className="dateInput"
        style={{
          ...style,
          minWidth: 208,
          display: 'inline-block',
          verticalAlign: 'top',
        }}
      >
        <RangePicker
          showTime
          size={size}
          value={[moment(start), moment(end)]}
          format={momentFormat}
          disabledDate={disabledDate}
          onChange={this.handleDateChange}
        />
      </span>
    );
  }
}
总结

通过引入 tempSelectedValue 作为中间状态,使用 getDerivedStateFromProps 方法代替过时的生命周期方法,有效地解决了组件重渲染和状态同步问题,成功避免了浏览器的卡死现象。这个方法不仅提高了组件的性能,还增强了代码的可维护性和可读性。

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值