Reactjs组件生命周期-从用户输入中获取数据

时间:2019-06-19 12:25:34

标签: javascript reactjs

我是Reactjs的新手,我尝试从搜索结果中构建过滤器系统。 当用户选择过滤器时,我想根据所选过滤器使用AJAX调用获取新数据。

我在过滤器的复选框中设置了事件处理函数,该复选框将组件的状态设置为。这使得React可以重新渲染组件。但是目前还没有最新数据。

componentWillUpdate()似乎很适合此用途,但除非使用UNSAFE_componentWillUpdate(),否则它将在下一版本(17)中弃用

如何在重新渲染组件之前获取最新数据?哪种生命周期方法是更好的选择?

第一组数据设置在我的index.html文件上

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Reactjs - Filtres component</title>
</head>
<body>
<div id="filtres" class="filtres" style="width:250px;"></div>
<script type="text/javascript">
    var filtres = [{
        "date": {
            "libelle": "Year",
            "buckets": {
                "date2018": {
                "name": "date[0]",
                "value": "2018",
                "title": 2018,
                "libelle": 2018,
                "nb": 1
             },
             "date2016": {
                "name": "date[1]",
                "value": "2016",
                "title": 2016,
                "libelle": 2016,
                "nb": 54
              },
              "date2015": {
                "name": "date[2]",
                "value": "2015",
                "title": 2015,
                "libelle": 2015,
                "nb": 70
              }
            }
          }
        },
        {
         // some filters
        }
      }];
    </script>
    <script src="dist/filtresComponent.js"></script>
</body>
</html>

FiltresComponent.js

import React from 'react'
import ReactDOM from 'react-dom'
import Filtres from './Filtres'

ReactDOM.render(<Filtres filtres={filtres} />, document.getElementById('filtres'));

Filtres.js

import React, { Component } from 'react'
import './Filtres.css'

import Crit from './Crit'

class Filtres extends Component {
  constructor(props) {
    super(props);
    this.state = {
      filtres : this.props.filtres,
      appliedFiltres : {}
    }
  }

  addFiltre = (filtreName, filtreValue) => {
    console.log('addFiltre from FiltresComponent !!');
    console.log('We add : ');
    console.log('filtreName :' + filtreName + ' ,value : ' + filtreValue);

    this.setState((state) => {
      return {appliedFiltres: Object.assign(state.appliedFiltres, {[filtreName]: filtreValue})}
    });

    console.log(this.state);

  }

  // before re-rendering sounds good but will be deprecated on reactjs 17
  componentWillUpdate = () => {
    console.log('componentWillUpdate');
    // Fetching before rendering ?
  }


  render() {
    console.log('render Filtres.js');
    return ([
      this.state.filtres.map((crit, index) =>  {
        let libelle = crit[Object.keys(crit)].libelle;
        let critValues = Object.values(crit[Object.keys(crit)].buckets);
        return <Crit key={index} libelle={libelle} critValues={critValues} addFiltre={this.addFiltre}/>
      })
    ])
  }
}

export default Filtres

Crit.js

import React, { Component } from 'react'


class Crit extends Component {

  static defaultProps = {
    open : true
  }

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

  showHideCrit = (e) => {
    if(this.state.open){
      e.target.nextElementSibling.style.display = 'none';
      this.setState({ open: false });
    }else{
      e.target.nextElementSibling.style.display = 'flex';
      this.setState({ open: true });
    }
  }

  addFiltre = (e) => {
    console.log('addFiltre from CritComponent !!');
    // User chosen filter
    let filtreName = e.target.name;
    let filtreValue = e.target.value;
    // LiftUp
    this.props.addFiltre(filtreName, filtreValue);
  }

  render() {
    console.log('render Crit.js');
    return ([
      <div className="crit">
        <a className={"js-head_crit " + (this.state.open ? 'open' : '' )+""} onClick={this.showHideCrit}>{this.props.libelle}</a>
        <div className="crit-values">
          {
            this.props.critValues.map((critValue,index) => {
              return (                
                  <div key={index} className="crit-value" data-count={critValue.nb}>
                      <input type="checkbox" name={critValue.name} value={critValue.value} onChange={this.addFiltre}/>
                      <label className="crit-libelle">
                          {critValue.libelle}
                          <span className="crit-nb">{critValue.nb}</span>
                      </label>
                  </div>                
              )
            })
          }
          </div>
      </div>
    ])
  }
}

export default Crit

输出

Console output

用户要按年份过滤:2015
我使用this.setState将date [2]:2015添加到了AppliedFiltres中
然后我想使用过滤器year = 2015来获取数据
最终重新渲染具有新值的组件

1 个答案:

答案 0 :(得分:0)

一种可能的解决方案是在将新过滤器设置为状态后立即触发获取操作,您可以通过调用this.setState方法调用来实现:

  addFiltre = (filtreName, filtreValue) => {
    // ...other codes
    this.setState(
      {},  // state update value 
      this.fetchData() // The function to trigger the AJAX call
    );
  }

注意:无论是否触发了AJAX调用,都应进行重新渲染;在渲染之前,您不应该等待AJAX​​调用完成,因为这会使您的应用无法使用(和痛苦)一段时间(直到AJAX调用完成)。

为确保良好的用户体验并避免显示过时的数据,可以在从服务器获取数据时显示可能正在加载的组件(可以像文本一样简单:loading...)。需要一个状态值来跟踪AJAX进程。 在下面的代码块中,我向状态添加了一个fetchingData布尔值,您可以使用它来跟踪何时进行数据提取以及何时进行数据提取。

class Filtres extends Component {

  constructor(props) {
    // ...other codes
    this.state = {
      // ...other states
      fetchingData: false,
    };
  }

  // ...other methods

  fetchData() {
    // set fetchingData to true as soon as the AJAX process starts
    this.setState({ fetchingData: true });
    // make ajax call with set filters
    // when ajax call is done, set it back to false 
    this.setState({ fetchingData: false });
  }

  render() {
    if(this.state.fetchingData) {
      // display loading component
    } else {
      // display the current data
    }

  // ...other methods
};