簡體   English   中英

React:我應該在哪個生命周期掛鈎上解析新接收到的數據?

[英]React: On which lifecycle hook should I parse new received data?

我正在嘗試解析從Firebase接收的數據,並將此新數據傳遞給組件。 數據以承諾方式異步獲取。 我遇到的問題是,即使我已經設置了componentDidMount並調用了函數來解析那里的數據,也沒有第一次呈現它。

我從firebase收到的數據如下:

faults: [{
  name: "Foo",
  status: "Open"
  type: "type1"
},
{
  name: "Bar",
  status: "Open"
  type: "type2"
}],
types: [{
  key: "type1",
  type: "Accident"
},
{
  key: "type2",
  type: "Crash"
}]

正如你可以看到我需要解析的數據替換type與正確名稱故障的types

為此,我有一個解析數據並設置狀態的函數。 這是該代碼:

parseFields() {
    let parsedFields = [];
    this.props.fields.forEach((field) => {
      const typeSelected= this.props.estados.find(element => element.key === field.type) || '';

      let parsedField = Object.assign({}, field);

      parsedField['type'] = typeSelected.type;

      parsedFields.push(parsedField);
    });
    this.setState({data: parsedFields});
  }

componentDidMountcomponentWillReceiveProps上調用此函數,但是在組件裝入時,不會顯示任何數據。 但是,當組件接收到新的道具時,它將正確顯示。

難道我做錯了什么? 我也嘗試過在componentWillMount上調用此函數,但是對於第一個渲染它不起作用。

更新

根據要求,這是組件代碼:

import React from 'react'

import Table from './Table';

class FaultList extends React.Component {
  constructor(props) {
    super(props);

    this.columns = [
      {
        name: 'Name',
        field: 'name'
      },
      {
        name: 'Type',
        field: 'type'
      },
      {
        name: 'Status',
        field: 'status'
      }
    ];

    this.state = {
      faults: []
    };

    this.parseFields = this.parseFields.bind(this);
  }

  parseFields() {
    let parsedFields = [];
    this.props.fields.forEach((field) => {
      const typeSelected= this.props.types.find(element => element.key === field.type) || '';

      let parsedField = Object.assign({}, field);

      parsedField['type'] = typeSelected.type;

      parsedFields.push(parsedField);
    });
    this.setState({data: parsedFields});
  }

  componentDidMount() {
    this.parseFields();
  }

  componentWillReceiveProps() {
    this.parseFields();
   }

  render() {
    return(
      <Table
        data={this.state.faults}
        columns={this.columns}
        handleClick={this.props.handleClick}
        />
    );
  }
}

export default FaultList;

這是負責處理在父組件中處理的數據提取的代碼:

componentDidMount() {
    this.faultsRef= ref.child('faults');

    this.faultsRef.on('value', (snap) => {
      let faults= [];
      snap.forEach((child) => {
        let fault= child.val();
        let key = child.key;
        const finalFault = update(fault, {$merge: {key}});
        faults.push(finalFault);
      });
      this.setState({faults});
    });

    get('types')
    .then((types) => {
      this.setState({types});
    });
  }

get函數的代碼是:

function get(node) {
  return ref.child(node).once('value')
  .then((snap) => {
    let list = [];

    snap.forEach((child) => {
      let object = child.val();
      let key = child.key;
      const finalObject = update(object , {$merge: {key}});
      list .push(finalObject);
    });

    return list;
  });
}

更新2:

我注意到一些非常非常奇怪的事情。 如果我在父組件的“ componentDidMount”中重新排序一些代碼,然后首先檢索類型列表,然后獲取錯誤列表,則第一次重新渲染正確,但沒有解析類型,所以我我的桌子上有空單元格。

我認為您應該在Table組件上使用this.state.data而不是this.state.faults

  <Table
    data={this.state.data}
    columns={this.columns}
    handleClick={this.props.handleClick}
    />

如果我正確地理解了您的組件, FaultList不會異步執行任何操作,而只是從父級接收道具。 鑒於此,您可以通過使FaultList成為無狀態並僅直接解析render的數據來簡化操作。 每當組件接收到新的道具時,組件將重新渲染(即:將調用render ),並且數據將被重新解析。

class FaultList extends React.Component {
  constructor(props) {
    super(props);

    this.columns = [
      ...
    ];

    this.parseFields = this.parseFields.bind(this);
  }

  // You no longer need `componentDidMount` and `componentWillReceiveProps`

  parseFields() {
    let parsedFields = [];
    this.props.fields.forEach((field) => {
      const typeSelected= this.props.types.find(element => element.key === field.type) || '';

      let parsedField = Object.assign({}, field);
      parsedField['type'] = typeSelected.type;
      parsedFields.push(parsedField);
    });

    // Note: we are now returning the value instead of setting `state`.
    return parsedFields;
  }

  render() {        
    return(
      <Table
        data={this.parseFields()}
        columns={this.columns}
        handleClick={this.props.handleClick}
      />
    );
  }
}

export default FaultList;

我發現了問題所在。 正如Bartek提到的那樣,Table組件應該引用狀態,因此我要做的就是將parseFields移動到父組件,並在每次Firebase檢索新數據時調用它。 這是該代碼:

class FaultsView extends React.Component {
  constructor(props) {
    super(props);

    this.faultsRef = null;

    this.state = {
      faults: [],
      parsedFaults: [],
      types: []
    };

    this.parseFields = this.parseFields.bind(this);
  }

  componentDidMount() {
    get('types')
    .then((types) => {
      this.setState({types});
    });

    this.faultsRef = ref.child('faults');

    this.faultsRef.on('value', (snap) => {
      let faults= [];
      snap.forEach((child) => {
        let fault= child.val();
        let key = child.key;
        const finalFault = update(fault, {$merge: {key}});
        faults.push(finalFault);
      });
      this.setState({faults});
      // This was the fix!
      this.parseFields();
    });
  }

  componentWillUnMount() {
    this.faultsRef.off();
  }

  parseFields() {
    let parsedFields = [];
    this.props.fields.forEach((field) => {
      const typeSelected= this.props.types.find(element => element.key === field.type) || '';

      let parsedField = Object.assign({}, field);

      parsedField['type'] = typeSelected.type;

      parsedFields.push(parsedField);
    });
    this.setState({data: parsedFields});
  }

  render() {
    return (
      <div>
        <FaultList
          faults={this.state.parsedFaults}
          handleClick={this.handleClick}/>
      </div>
    );
  }
}

export default FaultsView;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM