从 React props 获取数据 [英] Get data from React props

查看:57
本文介绍了从 React props 获取数据的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

 componentDidMount() {this.setState({开始日期:时刻().subtract(30, '天').startOf('天'),结束日期:moment().endOf('day'),selectedSeverity:空,isChecked: 真,});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';从'prop-types'导入T;从'react-redux'导入{连接};从'react-router-dom'导入{ withRouter };从反应时刻"导入{时刻};从'i18next'导入{t};从'lodash'导入_;从'cloud-modules-user/build/TimezoneLabel'导入{ TimezoneLabel };从'semantic-ui-react'导入{表,收音机};从'cloud-modules-user/build/RangeDatePicker'导入{ RangeDatePicker};从'cloud-modules-user/build/Alerts'导入{SeverityFilter};从 '../Redux/Household.actions' 导入 { fetchHouseholdAlerts };const alertSeverityText = ({严重性}) =>严重性<3 ?错误":警告";const alertsBySeverity = 警报 =>{const groupedAndCounted = _.countBy(alerts, alertSeverityText);返回严重性 =>groupedAndCounted[严重性] ||0;};const alertSeverityColor = {错误:'#e05567',警告:'#f9b233',};导出类 HouseholdAlertsPure 扩展 React.Component {构造函数(道具){超级(道具);this.state = {tableAlerts: props.householdAlerts}}静态 propTypes = {家庭警报:T.arrayOf(T.object).isRequired,};componentDidMount(prevProps) {this.setState({开始日期:时刻().subtract(30, '天').startOf('天'),结束日期:moment().endOf('day'),selectedSeverity:空,isChecked: 真,});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 });常量{//eslint-disable-next-line no-shadowfetchHouseholdAlerts,匹配:{参数},} = this.props;fetchHouseholdAlerts(params.deviceGroupId, startDate, endDate);};selectOngoingAlerts = (e, data) =>{const { isChecked } = this.state;this.setState( {isChecked : !isChecked} );const {householdAlerts } = this.props;//检查闹钟是否正在进行如果(已检查){//过滤正在进行的警报让filteredHouseholdAlerts = homeAlerts.filter((alert) => alert.setTimestamp {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} )}使成为() {console.log('test', this.props.householdAlerts)const { startDate, endDate } = this.state;const dateInitialized = startDate &&结束日期;//在安装组件之前不会设置日期.if (!datesInitialized) 返回空值;const {householdAlerts } = this.props;常量标签 = {来自:t('householdAlertsTimeRangeFrom'),to: t('householdAlertsTimeRangeTo'),};const numberOfAlert = alertsBySeverity(householdAlerts);返回 (<div className="警报表"><section className="alerts-buttons"><div className="ongoing-box"><Radio toggle className="ongoing-checkbox"标签=正在进行的警报"值={ !this.state.isChecked }onChange={this.selectOngoingAlerts}></收音机>

<SeverityFilter className="severity--button"onChange={this.handleOnChangeSeverity}值={this.state.selectedSeverity}选项={this.state.selectedSeverity ||'全部'}></SeverityFilter>{ this.setAlertForTable() }<div className="time-range">{t('householdAlertsTimeRange')}</div><RangeDatePickerid="rangeDateSelector"标签={标签}onChange={e =>this.onChangeDate(e)}selectedDateRange={[startDate, endDate]}filterDate={date =>时刻()>日期}/></节><div className="alert-table--statuses"><div aria-label="错误">

<div aria-label="警告">

<表格可排序><表头><表.行><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><表格.正文>{householdAlerts &&homeAlerts.length !== 0 ?(_.地图(家庭警报,({ID,严重性,设备名称,名称,设置消息,设置时间戳,}) =>(<Table.Row key={id}><表格单元格className="alert-table--column-severity"文本对齐=右">

);}}const mapStateToProps = state =>({家庭警报:state.HouseholdReducer.householdAlerts,});const mapDispatchToProps = { fetchHouseholdAlerts };导出默认 withRouter(连接(mapStateToProps,mapDispatchToProps)(HouseholdAlertsPure),);

解决方案

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

<小时>

 导出类 HouseholdAlertsPure 扩展 React.Component {构造函数(道具){超级(道具);//状态的初始值this.state = {tableAlerts: [],开始日期:空,结束日期:空,selectedSeverity:空,isChecked: 假}}componentDidMount() {//在组件第一次加载时为状态声明的值this.setState({开始日期:时刻().subtract(30, '天').startOf('天'),结束日期:moment().endOf('day'),selectedSeverity:空,isChecked: 真,tableAlerts:this.props.householdAlerts});componentDidUpdate() {//每当 prop 值改变时调用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} );//现在,{ isChecked } 仍然是指构造上面的方法和上一个值...//对于更多的组合方法,考虑在渲染时直接执行过滤逻辑而无需操作状态如果(!isChecked){this.setState( { tableAlerts: tableAlerts.filter((alert) => alert.setTimestamp 

<小时>

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

How to get data from props and be sure that data arrived properly. My issue is that in my class component I receive alarms from props and then I want to render table with the alarms, props sets asynchronously and I want to be sure that the data arrived and that I will be able to set a state. Below is my not nice try to solve it, but does not work (both console.log shows empty array):

  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 })
    }
  }

The whole component:

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),
);

解决方案

It is bad practice to set initial values to state at the constructor, therefore use lifeCycles as componentDidMount or componentDidUpdate instead to manipulate the state.


 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...
}


Now at render, { this.state.tableAlerts } should contain the correct information

这篇关于从 React props 获取数据的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆