簡體   English   中英

如何在 React 中使用 async/await 等待數據完成獲取

[英]How to wait for data to finish fetching with async/await in React

我自己對這個問題的回答有效,我的回答中包含的 Pedrag 的評論也有效

我正在執行 http 請求調用,並且在 http 響應返回之前不想顯示該頁面(請求調用是 getRoadmaps)。 我有一個稱為“加載”的 redux 狀態來確定響應是否回來了? 關於如何在我的代碼中實現它的任何見解? 我的其他 redux 狀態是路線圖,其中包含一個也稱為路線圖的對象(抱歉造成混淆)。

PS我看到一些答案說要做(偽代碼):如果沒有加載顯示加載屏幕否則在渲染中加載正常屏幕。 但是我的問題不存在於渲染中,而是在我做的 componentWillMount() 中

this.props.getRoadmaps() 

然后在我做的 3 行之后

console.log(this.displayRoadmap[0].roadmap[0])

如果 getRoadmaps() 完成,應該成功記錄路線圖,似乎調用了 getRoadmaps() 但隨后程序繼續運行而 getRoadmaps() 沒有完全完成,這導致我的 displayRoadmap 未定義。 這也會導致一些奇怪的現象,比如如果我從一個屏幕進入這個組件它總是有效但如果我刷新頁面它就不起作用

import React, { Component } from "react";
import Tree from "./Tree";
import TreeSidebar from "./TreeSidebar";
import { withRouter } from "react-router-dom";
import { connect } from "react-redux";
import { getRoadmaps } from "../actions/roadmapAction";
class OneRoadmap extends Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: this.props.roadmap.loading,
      roadmapName: "click a white circle to show more!",
      roadmapImg:
        "https://cdn3.iconfinder.com/data/icons/harmonicons-06/64/plus-circle-512.png",
      roadmapDetail: [{ text: "Click on something" }, { text: "hi" }],
      treeData: //deleted,just the default big json object
   };
  }

  componentWillMount() {
    this.props.getRoadmaps();

    var location1 = this.props.location.pathname;
    var n = location1.slice(9);

    var current_roadmaps = this.props.roadmap.roadmaps;

    this.displayRoadmap = current_roadmaps.filter(
      eachRoadmap => eachRoadmap._id == n
    );
    // now we have a roadmap
    console.log(this.displayRoadmap[0].roadmap[0]);
    this.setState({ treeData: this.displayRoadmap[0].roadmap[0] });
    console.log("is good");
    console.log(this.props.loading);
  }

  componentDidMount() {}

  handle_on_click_change = d => {
    this.setState({ roadmapName: d.data.name });
    this.setState({ roadmapImg: d.data.img });
    if (d.data.details == undefined) {
      this.setState({
        roadmapDetail: [{ text: "The author did not put anything here" }]
      });
    } else {
      this.setState({ roadmapDetail: d.data.details });
    }
  };

  render() {
    return (
      <div>
        {console.log(this.state.loading)}
        <ul>
          <li styles={{ float: "left" }}>
            <div>
              {console.log(this.state.treeData)}
              <Tree
                on_click_change={this.handle_on_click_change}
                roadmapData={this.state.treeData}
              />
            </div>
          </li>
          <li styles={{ float: "right" }}>
            <div>
              <TreeSidebar
                displayName={this.state.roadmapName}
                displayImg={this.state.roadmapImg}
                displayDetail={this.state.roadmapDetail}
              />
            </div>
          </li>
        </ul>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  roadmap: state.roadmap
});

export default connect(
  mapStateToProps,
  { getRoadmaps }
)(OneRoadmap);

就我個人而言,我如何做到這一點我使用 CSS 樣式我不知道這是否是最好的方法,但它對我有用,我會做這樣的事情

 this state = {
      loaderStyle: 'block',
      contentStyle: 'none'
 }
componentDidMount() {
    If(this.displayRoadmap[0].length > 0) {
       this.setsState({loaderStyle: 'none', contentStyle: 
          'block:
    } else /// do something

};

在我的渲染函數中,我會這樣做

 <Loader style={{display: this.state.loaderStyle}}/>

 <Content style={{display: this.state.contentStyle}}>. 
 </Content>

首先也是最重要的,不要使用componentWillMount ,而是使用componentDidMount UNSAFE_componentWillMount()是舊版本,將在版本 17 中刪除。現在,在下一個問題上,您希望通過將loading狀態設置為 true 來啟動頁面。

this.state = {
      loading: true,
      roadmapName: "click a white circle to show more!",
      roadmapImg:
        "https://cdn3.iconfinder.com/data/icons/harmonicons-06/64/plus-circle-512.png",
      roadmapDetail: [{ text: "Click on something" }, { text: "hi" }],
      treeData: //deleted,just the default big json object
   };

之后,您需要稍微調整渲染方法以支持條件渲染:

render() {
        if (this.state.loading) {
            return <LoadingBar />;
        }
        return (
            <div>
                <ul>
                    <li styles={{ float: 'left' }}>
                        <div>
                            {console.log(this.state.treeData)}
                            <Tree
                                on_click_change={this.handle_on_click_change}
                                roadmapData={this.state.treeData}
                            />
                        </div>
                    </li>
                    <li styles={{ float: 'right' }}>
                        <div>
                            <TreeSidebar
                                displayName={this.state.roadmapName}
                                displayImg={this.state.roadmapImg}
                                displayDetail={this.state.roadmapDetail}
                            />
                        </div>
                    </li>
                </ul>
            </div>
        );
    }

現在,只要您的數據准備就緒,您就可以簡單地執行this.setState({ loading: false }) ,並且 render 方法將返回不是加載欄的任何內容。 所以在你的具體情況下:

this.setState({ treeData: this.displayRoadmap[0].roadmap[0], loading: false });

這可以通過 React 高階組件輕松實現,如下所示。

withLoadingScreen.js

import * as React from "react";

const withLoadingScreen = WrappedComponent => {
  return class LoadingScreen extends React.Component {
    render() {
      if (this.props.loading) return <div className="pre-loader" > Loading... </div>
      return <WrappedComponent {...this.props} />;
    }
  };
};

export default withLoadingScreen;

對您的組件按如下方式使用 HOC

export default compose(
  connect(mapStateToProps, mapActionCreators),
  withLoadingScreen
)(OneRoadmap)

您也可以將自定義參數傳遞給 HOC。 有關更多示例,請訪問以下鏈接。 通過引用它們來根據需要對代碼進行更改。

https://medium.com/@peterpme/learning-higher-order-components-in-react-by-building-a-loading-screen-9f705b89f569

https://medium.com/@Farzad_YZ/handle-loadings-in-react-by-using-higher-order-components-2ee8de9c3deb

我檢查了 elraphty 的回答,因為他確實回答了我的部分問題,而且他還希望我檢查他的回答。 無論如何,如果您在獲取數據並等待數據完成獲取時遇到問題,這里有一個完整的示例,說明我是如何做到的。 Predrag Beocanin 的評論作品:

fetch('some_url', { method: 'GET' }).then(res = res.json()).then(data => { // some parse here; return parsed}

這是我的操作方法(使用 axios 而不是 mech,將請求發送到另一個完全不同的文件 /api/roadmap,然后使用 Redux 更新商店。

在 OneRoadmap.js 中,這是我需要獲取數據的組件,我調用它來獲取數據:

  async componentDidMount() {
await this.props.getRoadmaps();
.....
}

這使得我們將運行 this.props.getRoadmaps() 並等到該行完成后再轉到下一行。 如果你不放置 async/await,this.props.getRoadmaps() 會觸發,但是 componentDidMount() 中的代碼會立即繼續,沒有 this.props.getRoadmaps() 來完成數據獲取然后更新狀態。 現在,當然,Predrag 的答案肯定會解決這個問題,但如果您想在不同的文件中使用 redux 進行數據獲取和狀態更新(比如我),請繼續閱讀.

這就是 getRoadmaps() 所做的,它位於名為 RoadmapActions.js 的文件中:

    export const getRoadmaps = () => dispatch => {
  dispatch(setRoadmapsLoading());
  return axios
    .get("/api/roadmaps")
    .then(res => dispatch({ type: GET_ROADMAPS, payload: res.data }));
};

這表示我們將向“/api/roadmaps”發送一個get請求,然后從get請求中獲取返回數據,然后向redux store發送一個dispatch,它會更新store狀態,我們最終將在OneRoadmap.js。 這是 /api/roadmaps get 請求返回的內容:

router.get("/", (req, res) => {
Roadmap.find()
.sort({ date: -1 })
.then(roadmaps => res.json(roadmaps));
});

Roadmap.find() 進入我們的 mongo 數據庫並檢索所有路線圖項目,然后我們將其返回到調用它的任何地方。

使用返回的數據,我們將帶有該數據的調度發送到減速器,這就是 GET_ROADMAPS() 所做的,GET_ROADMAPS 位於 roadmapReducer.js 中:

const initialState = {
  roadmaps: [],
  loading: false,
  current_roadmap: ""
};

export default function(state = initialState, action) {


switch (action.type) {
    case GET_ROADMAPS:
      return {
        ...state,
        roadmaps: action.payload,
        loading: false
      };


}

然后,就是這樣,您的 redux 存儲狀態已更新,並且由於我將 OneRoadmap.js 與 state.roadmap 連接起來,因此我可以在代碼中自由使用它。

暫無
暫無

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

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