javascript - 从 React props 获取数据

标签 javascript reactjs setstate

如何从 props 获取数据并确保数据正确到达。我的问题是,在我的类组件中,我从 props 接收警报,然后我想用警报渲染表, Prop 设置异步,我想确保数据到达并且我能够设置一个状态。下面是我不太好的尝试解决它,但不起作用(两个 console.log 显示空数组):

  componentDidMount() {
    this.setState({
      startDate: moment()
        .subtract(30, 'days')
        .startOf('day'),
      endDate: moment().endOf('day'),
      selectedSeverity: null,
      isChecked: true,
    });

    if(this.state.tableAlerts.length === 0){
      console.log('tableAlerts', this.state.tableAlerts)
      console.log('householdAlerts', this.props.householdAlerts)
      this.setState({ tableAlerts: this.props.householdAlerts })
    }
  }

整个组件:

import React, { useState } from 'react';
import T from 'prop-types';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { moment } from 'react-moment';
import { t } from 'i18next';
import _ from 'lodash';
import { TimezoneLabel } from 'cloud-modules-user/build/TimezoneLabel';
import { Table, Radio } from 'semantic-ui-react';
import { RangeDatePicker } from 'cloud-modules-user/build/RangeDatePicker';
import { SeverityFilter } from 'cloud-modules-user/build/Alerts';
import { fetchHouseholdAlerts } from '../Redux/Household.actions';

const alertSeverityText = ({ severity }) =>
  severity < 3 ? 'error' : 'warning';

const alertsBySeverity = alerts => {
  const groupedAndCounted = _.countBy(alerts, alertSeverityText);
  return severity => groupedAndCounted[severity] || 0;
};

const alertSeverityColor = {
  error: '#e05567',
  warning: '#f9b233',
};

export class HouseholdAlertsPure extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      tableAlerts: props.householdAlerts
    }
  }

  static propTypes = {
    householdAlerts: T.arrayOf(T.object).isRequired,
  };

  componentDidMount(prevProps) {
    this.setState({
      startDate: moment()
        .subtract(30, 'days')
        .startOf('day'),
      endDate: moment().endOf('day'),
      selectedSeverity: null,
      isChecked: true,
    });

    console.log('prevprops', prevProps)

    // if(this.props.householdAlerts !== prevProps.householdAlerts){

    //   this.setState({ tableAlerts: this.props.householdAlerts })

    // }


    // if(this.state.tableAlerts.length === 0){
    //   console.log('tableAlerts', this.state.tableAlerts)
    //   console.log('householdAlerts', this.props.householdAlerts)
    //   this.setState({ tableAlerts: this.props.householdAlerts })
    // }
  }

  onChangeDate = e => {
    const startDate = moment(e.startDate).startOf('day');
    const endDate = moment(e.endDate).endOf('day');
    this.setState({ startDate, endDate });
    const {
      // eslint-disable-next-line no-shadow
      fetchHouseholdAlerts,
      match: { params },
    } = this.props;
    fetchHouseholdAlerts(params.deviceGroupId, startDate, endDate);
  };

  selectOngoingAlerts = (e, data) => {
    const { isChecked } = this.state;
    this.setState( {isChecked : !isChecked} );

    const { householdAlerts } = this.props;
    // check whether alarm is ongoing
    if(isChecked){
      // filter ongoing alerts
      let filteredHouseholdAlerts = householdAlerts.filter((alert) => alert.setTimestamp < alert.clearTimestamp)
      this.setState( {tableAlerts: filteredHouseholdAlerts} )
    }else{
      // show all alerts, without any filter
      this.setState({tableAlerts: householdAlerts});
    }
  }

  handleOnChangeSeverity = (e, selectedOption ) => {

    console.log('e', e)
    this.setState( {selectedSeverity: e.option} )
    console.log('selectedSeverity', this.state.selectedSeverity)

  };

  setAlertForTable = () => {
    // if(this.state.alertsInitialised == true) return;
    console.log('setAlertForTable')
    // this.setState ( {alertsInitialised: true} )    
  }

  render() {

    console.log('test', this.props.householdAlerts)
    const { startDate, endDate } = this.state;
    const datesInitialized = startDate && endDate;
    // The dates are not set until the component is mounted.
    if (!datesInitialized) return null;

    const { householdAlerts } = this.props;
    const labels = {
      from: t('householdAlertsTimeRangeFrom'),
      to: t('householdAlertsTimeRangeTo'),
    };
    const numberOfAlert = alertsBySeverity(householdAlerts);



    return (
      <div className="alert-table">
        <section className="alerts-buttons">
          <div className="ongoing-box">
            <Radio toggle className="ongoing-checkbox"
              label="Ongoing alerts"
              value={ !this.state.isChecked }
              onChange={this.selectOngoingAlerts}
            ></Radio>
          </div>
          <SeverityFilter className="severity--button"
            onChange={this.handleOnChangeSeverity}
            value={this.state.selectedSeverity}
            option={this.state.selectedSeverity || 'all'}
          ></SeverityFilter>

          { this.setAlertForTable() }

          <div className="time-range">{t('householdAlertsTimeRange')}</div>
          <RangeDatePicker
            id="rangeDateSelector"
            labels={labels}
            onChange={e => this.onChangeDate(e)}
            selectedDateRange={[startDate, endDate]}
            filterDate={date => moment() > date}
          />
        </section>
          <div className="alert-table--statuses">
            <div aria-label="error">
              <div
                className="alert-table--statuses-item"
                style={{ backgroundColor: alertSeverityColor.error }}
              />
              <span className="alert-table--statuses-item-number">
                {numberOfAlert('error')}
              </span>
            </div>
            <div aria-label="warning">
              <div
                className="alert-table--statuses-item"
                style={{ backgroundColor: alertSeverityColor.warning }}
              />
              <span className="alert-table--statuses-item-number">
                {numberOfAlert('warning')}
              </span>
            </div>
          </div>

        <Table sortable>
          <Table.Header>
            <Table.Row>
              <Table.HeaderCell style={{ width: '116px' }}>
                {t('householdAlertsSeverity')}
              </Table.HeaderCell>
              <Table.HeaderCell textAlign="left">
                {t('householdAlertsDevice')}
              </Table.HeaderCell>
              <Table.HeaderCell textAlign="left">
                {t('householdAlertsAlertName')}
              </Table.HeaderCell>
              <Table.HeaderCell textAlign="left">
                {t('householdAlertsAlertsMessage')}
              </Table.HeaderCell>
              <Table.HeaderCell textAlign="right">
                {t('householdAlertsTimestamp')}
              </Table.HeaderCell>
            </Table.Row>
          </Table.Header>
          <Table.Body>
            {householdAlerts && householdAlerts.length !== 0 ? (
              _.map(
                householdAlerts,
                ({
                  id,
                  severity,
                  deviceName,
                  name,
                  setMessage,
                  setTimestamp,
                }) => (
                  <Table.Row key={id}>
                    <Table.Cell
                      className="alert-table--column-severity"
                      textAlign="right"
                    >
                      <div
                        className="alert-table--column-severity__status"
                        style={{
                          backgroundColor:
                            alertSeverityColor[alertSeverityText({ severity })],
                        }}
                      />
                    </Table.Cell>
                    <Table.Cell
                      className="alert-table--column-device"
                      textAlign="left"
                    >
                      {deviceName}
                    </Table.Cell>
                    <Table.Cell
                      className="alert-table--column-alert"
                      textAlign="left"
                    >
                      {name}
                    </Table.Cell>
                    <Table.Cell
                      className="alert-table--column-message"
                      textAlign="left"
                    >
                      {setMessage}
                    </Table.Cell>
                    <Table.Cell
                      className="alert-table--column-timestamp"
                      textAlign="right"
                    >
                      {moment(setTimestamp).format('DD-MM-YYYY HH:mm')}
                    </Table.Cell>
                  </Table.Row>
                ),
              )
            ) : (
              <Table.Row>
                <Table.Cell colSpan={7}>
                  {t('householdAlertsMessageNoAlerts')}
                </Table.Cell>
              </Table.Row>
            )}
          </Table.Body>
        </Table>
        <section className="timezone-wrapper">
          <TimezoneLabel />
        </section>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  householdAlerts: state.HouseholdReducer.householdAlerts,
});

const mapDispatchToProps = { fetchHouseholdAlerts };

export default withRouter(
  connect(mapStateToProps, mapDispatchToProps)(HouseholdAlertsPure),
);

最佳答案

在构造函数中设置初始值是不好的做法,因此使用 lifeCycles 作为 componentDidMount 或 componentDidUpdate 来操作状态。

<小时/>
 export class HouseholdAlertsPure extends React.Component {

 constructor(props) {
  super(props);
  // initial values for state
  this.state = {
  tableAlerts: [],
  startDate: null,
  endDate: null,
  selectedSeverity: null,
  isChecked: false      
 }
}

componentDidMount() {
 // values declared for state at component first load
 this.setState({
  startDate: moment()
    .subtract(30, 'days')
    .startOf('day'),
  endDate: moment().endOf('day'),
  selectedSeverity: null,
  isChecked: true,
  tableAlerts: this.props.householdAlerts
});

componentDidUpdate() {
// called whenever prop value changed
 if(this.props.householdAlerts !== this.state.tableAlerts) 
      this.setState({ tableAlerts: this.props.householdAlerts })
}

selectOngoingAlerts = (e, data) => {
 const { isChecked, tableAlerts } = this.state;
 this.setState( {isChecked : !isChecked} );
 // right now, { isChecked } still refer to construct abouve methond and prev value... 
// for more consist aproach, consider do the filtering logic direct at render without manipulate state
 if(!isChecked) { 
  this.setState( { tableAlerts: tableAlerts.filter((alert) => alert.setTimestamp < alert.clearTimestamp)} )
 } else { this.setState({tableAlerts}) }
}
 ...rest class...
}
<小时/>

现在在渲染时,{ this.state.tableAlerts } 应该包含正确的信息

关于javascript - 从 React props 获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60953545/

相关文章:

javascript - 闭包内的长函数名

javascript - 为什么忽略表格指定的水平尺寸?

javascript - 自动加载随机页面

javascript - 如何处理条件组件内的 onClick 事件

javascript - 如何在 React 上设置具有撤消操作的初始状态?

javascript - React 中setState 的这两种updater 函数是否相等?

javascript - Lint 和 Prettier 存储库没有大规模合并冲突

reactjs - 我应该在后端还是前端过滤数据?

javascript - 阻止 React 高阶组件在包装组件之前安装?

javascript - 状态更新可能是异步的