反応でデータレンダリングを適切にタイミング調整する方法は?


8

Open Dataからデータをプルして、クイックヒートマップをまとめようとしています。その過程で、いくつかの統計を追加したいと思います。データがあり、マップをレンダリングできるという点で、ほぼすべてがうまくいきますが、データが入るまでに時間がかかるため、データを取得した後の計算の処理方法がわかりません。どのように設定すれば、まだデータを受信して​​いない場合でも、状態変数に対して関数を実行できますか?現在、StatCardに小道具として渡される数値としてnullを取得しています

以下は私の試みです:

App.js

  import React, { Component } from 'react';
import Leaf from './Leaf';
import Dates from './Dates';
import StatCard from './StatCard';
import classes from './app.module.css';

class App extends Component {

  constructor(props) {
    super(props);
    this.state = {
      data:[],
      cleanData:[],
      dateInput: '2019-10-01',
      loading: false,
      totalInspections: null,
      calculate: false
    };
  }

  componentDidMount() {
    try {
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
  }


  fetchData=()=>{
    const requestData = async () => {
      await fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
        .then(res => res.json())
        .then(res =>
          //console.log(res)
          this.setState({ data: res, loading: true})
        )
    }

    const  calculateInspections = () => {
      this.setState({totalInspections: this.state.data.length})
    }

    //call the function
    requestData();

    if(this.state.data) {
      calculateInspections();
    }
  }

  handleDateInput = (e) => {
    console.log(e.target.value);
    this.setState({dateInput:e.target.value, loading: false}) //update state with the new date value
    this.updateData();
    //this.processGraph(e.target.value)
  }

  updateData =() => {
    this.fetchData();
  }

  LoadingMessage=()=> {
    return (
      <div className={classes.splash_screen}>
        <div className={classes.loader}></div>
      </div>
    );
  }


  //inspection_date >= '${this.state.dateInput}'& 
 // https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=inspection_date >= '2019-10-10T12:00:00' 

  render() {



    return (
      <div>

        <div>{!this.state.loading ? 
              this.LoadingMessage() : 
              <div></div>}
        </div>

        {this.state.totalInspections && <StatCard totalInspections={this.state.totalInspections} /> }

          <Dates handleDateInput={this.handleDateInput}/>
          <Leaf data={this.state.data} />

      </div>
    );
  }
}

export default App;

StatCard.js

import React from 'react';


const StatCard = ( props ) => {

    return (
        <div >
            { `Total Inspections: ${props.totalInspections}`}
        </div>
    )
};

export default StatCard;

修理を試みる

   componentDidMount() {
    try {
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
  }


  componentDidUpdate () {
    if(this.state.data) {
      this.setState({totalInspections: this.state.data.length})
    }
  }

  fetchData= async ()=>{
    const requestData = () => {
    fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
        .then(res => res.json())
        .then(res =>
          //console.log(res)
          this.setState({ data: res, loading: true})
        )
    }
    //call the function
    await requestData();

  }

あるthis.setState({ data: res, loading: true})にタイプミスrequestData機能は?データがフェッチloadingされるfalseときに設定されるべきではありませんか?
thgaskell

そのAタイプミスええ
LoF10

クエリパラメータの使用がAPIドキュメントに対応していることを確認しますか?
ジュリアン

はい、コードで確認できるように、データがフェッチされますが、これは問題ではありません。データがあります。問題は、calculateInspections()をいつ、どこで実行するかがわからないことです。これは、すべてのAPIデータを受信し、propsとしてstatCardに渡すときに実行する必要があるためです。
LoF10

codesandboxリンクを送ってください
TopW3

回答:


0

<StatCard />必要なデータがある場合にのみレンダリングします。

{this.state.totalInspections && <StatCard totalInspections={this.state.totalInspections} /> }

私はそれを試しましたがサイコロはありませんでした。this.state.dataがcomponentDidMount内に存在するが運がない場合にのみ、計算を実行しようとしました。私が今得ているのは、StatCardが0だった場合の0の数字だけです
LoF10

1
そうですね、それはあなたがpromise / asyncの動作がどのように機能するのか理解していないからです。await requestData()これをrequestData関数に直接追加する代わりに、を追加する必要がありasync fetchData = () => {}ます。さらに良いのfetchDataは、データをフェッチして状態に保存することだけです。次に、変更時にのみcomponentDidUpdateトリガーするために使用する必要がありますcalculateInspections()this.state.data
Chase DeAnda

Hey Chase、あなたが指摘したことを運用可能にしようとしていますが、まだ学んでいることは認めますが、どのように実装すればよいかわかりません。あなたが見て、正しい方向に向けることができれば、私の試みに私の試みを追加しましたか?
LoF10

0

まず、別の機能は必要ないと思いますcalculateInspections()。そのロジックをthenコールバックに入れることができます。

fetchData = () => {
  fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${this.state.dateInput}'&$limit=50000`)
    .then(res => res.json())
    .then(data => {
      this.setState({
        data: data,
        loading: true,
        totalInspections: this.state.data.length
      })
    })
}

第二にthis.state.totalInspectionsあなたが簡単にできるので、設定は事実上冗長です:

{this.state.data && <StatCard totalInspections={this.state.data.length} /> }

最後に、componentDidUpdate()反応が初めての場合はフックの使用を避けます。ほとんどの場合、足で自分を撃ちます。

現在、試行修復により、無限のレンダリングループが発生しました。これは、を呼び出すたびに、レンダリング後にライフサイクルフックsetState()が呼び出されるために発生しますcomponentDidUpdate()。しかし、componentDidUpdate()あなたの中でもう一度 setState()呼び出すと、同じライフサイクルフックへのフォローアップ呼び出しが発生し、ループが繰り返されます。

経験則に従って、内部で使用componentDidUpdate()して呼び出す必要がある場合はsetState()、必ずその前に停止条件を置いてください。あなたの場合、それは次のようになります:

componentDidUpdate () {
  if (this.state.data) {
    if (this.state.totalInspections !== this.state.data.length) {
      this.setState({ totalInspections: this.state.data.length })
    }
  }
}

0

したがって、問題は、非同期呼び出しの前にisLoading状態をSYNCHRONOUSLYに設定する必要があることです。

だからあなたのcomponentDidMountで:

componentDidMount() {
    try {
      this.setState({ loading: true }); // YOU NEED TO SET TRUE HERE
      this.fetchData();
    } catch (err) {
      console.log(err);
      this.setState({
        loading: false
      })
    }
}

これにより、呼び出しを行うとすぐにロードが行われます。それからあなたの呼び出しが行われ、その部分は非同期です。データがロードされるとすぐにロードが行われます

.then(data => {
  this.setState({
    data: data,
    loading: false, // THIS NEEDS TO BE FALSE
    totalInspections: this.state.data.length
  })
})

さらに:renderメソッドは複数のreturnステートメントを持つことができます条件付きのjsxの代わりに、読み込みレイアウトを返します

render() {

    if (this.state.loading) {
        return <div> I am loading </div>
    }

    return <div> Proper Content </div>;

}

0

これが私の解決策です。

class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            data: [],
            dateInput: '2019-10-01',
            loading: false,
            error: false
        };
    }

    async componentDidMount() {
        try {
            await this.fetchData(this.state.dateInput);
        } catch (err) {
            this.setState({ loading: false, error: true });
        }
    }

    fetchData = (date) => new Promise(resolve => {
        this.setState({ loading: true });
        fetch(`https://data.cityofnewyork.us/resource/p937-wjvj.json?$where=latitude > 39 AND latitude< 45 AND inspection_date >= '${date}'&$limit=50000`)
            .then(res => res.json())
            .then(res => {
                this.setState({ data: res, loading: false, error: false });
                resolve(res.data);
            });
    })

    handleDateInput = e => {
        this.setState({ dateInput: e.target.value }) //update state with the new date value
        this.fetchData(e.target.value);
    }

    render() {
        const { loading, data } = this.state;
        return (
            <div>
                {loading && (
                    <div className={classes.splash_screen}>
                        <div className={classes.loader}></div>
                    </div>
                )}
                {data && <StatCard totalInspections={data.length} />}
                <Dates handleDateInput={this.handleDateInput} />
                <Leaf data={data} />
            </div>
        );
    }
}

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.