簡體   English   中英

React 需要點擊兩次來渲染從 api 獲取的數據

[英]React need to click twice to render data fetched from api

我需要在鏈接到當前頁面的按鈕上單擊兩次,以便從 api 獲取數據進行渲染。 我正在使用 nivo / 圖表來可視化我的數據。

該組件從 api 中獲取公司列表,第二個 fetch 循環遍歷每個結果,為每個不同的公司獲取數據。

在第一次嘗試時,公司列表是在父組件上獲取的,此后每個子組件都會發生一個獲取請求(parent=list of chart components, child=Company Chart) ,但是在分頁過程中它沒有呈現正確所以我不得不將 state 提升到父組件,這次的問題是父組件在第一次單擊時沒有呈現,我必須雙擊例如鏈接按鈕,以便父組件會呈現。

我認為問題可能正在發生,因為可能存在與 componentDidMount 操作順序的錯誤同步,因為我確信第一個和第二個數據獲取(首先是公司獲取請求和第二個不同的公司獲取請求)同時執行,而不是而不是一個接一個。 所以我定向到 redux 並將我的應用程序架構為 redux 規則。 它沒有解決任何問題,仍然需要雙擊鏈接才能進行渲染。

現在我覺得我需要為 api 獲取過程添加一些等待/異步規則,但我不確定這是否可行,所以我非常感謝就如何解決這個小問題獲得第二意見,因為它有困擾我好幾個星期了。

我的減速機:

import { FETCH_COMPANIES } from '../actions/types';

const initialState = {
    next : null,
    prev : null,
    items : [],
    item : [],
}



export default function(state = initialState, action) {
    switch (action.type) {
        case FETCH_COMPANIES:
            return {
                ...state,
                items : action.payload.companies,
                next : action.payload.next,
                prev : action.payload.prev,
                
            }

        default:
            return state;
    }
}

我的 Store.js:

import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';


const initialState = {};
const middleware = [thunk];

const store = createStore(
    rootReducer,
    initialState,
    compose(
        applyMiddleware(...middleware)
    )
)


export default store;

我的行動:

import axios from 'axios';
import { FloatType } from 'three';
import { FETCH_COMPANIES } from './types'; 





export const fetchAllData = (url) => dispatch => {
    fetch(url)
    .then(res => res.json())
    .then(
        posts => 
        
        dispatch({
            type : FETCH_COMPANIES,
            payload : FetchCall(posts),
        }) 
    )
    

}

function FetchCall(res) {
    let next;
    let prev;
    try {
        next = res.next;
    }
    catch(err) {
        console.log(err)
    }
    try {
        prev = res.previous;
    }
    catch(err) {
        console.log(err)
    }

    const CompanyArray = Array()

    res.results.map(element => {
        axios.get(`https://API/${element.symbol}/`).then((res) => {
            const DataGroup = handleChartData(res.data)
            CompanyArray.push({
                'name' : element.symbol,
                'data' : DataGroup,
            })
        })
        
    });

    const ALL_DATA = {
        'next' : next,
        'prev' : prev,
        'companies' : CompanyArray,
    }

    return ALL_DATA;

}



function handleChartData(data) {
    DataGroup = Object()
    return DataGroup;
}

我的組件:

import React, { useState}  from 'react';
import { Card, Row, Col, Button } from 'antd';
import Chart from '../components/Chart';
import DetailCompany from './CompanyDetail';
import { connect } from 'react-redux';
import { fetchAllData } from '../actions/chartActions';
import PropTypes from 'prop-types';

class CompanyList extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            charts : this.props.charts
        }
    }
    
    componentWillMount() {

        try {
            this.props.fetchAllData("https://API/company/")
        }
        catch(err) {
            console.log(err)
        }
        
    };

 
    prevPage = () => {
        let toPage = this.props.prev
        this.props.fetchAllData(toPage)
       
    }
    nextPage = () => {
        let toPage = this.props.next
        
        this.props.fetchAllData(toPage)
        
    }

    

    

    
    render() {
        
        const chartItems = this.state.charts.map(chart => (
            <Col style={{margin:'0 0 75px 0'}} span={12} key={chart.name}>
                <h1 style={{lineHeight:'2em', margin:'0 0 0 70px'}}>{chart.name}</h1>
                <div className="chart-block">
                        
                        <Chart symbol={chart.name} 
                                data={chart.data.chartData}
                      >
                               
                        </Chart>       
                </div>
            </Col>
        ));
        return (
            <Card>
                <Row>
                    {chartItems}
                </Row>    
                <Row>
                    <Button disabled={(this.props.prev ? false : true )} onClick={() => {this.prevPage()}}>Previous</Button>
                    <Button onClick={() => {this.nextPage()}}>Next</Button>
                </Row>
            </Card>
        )
    }
}


CompanyList.propTypes = {
    fetchAllData : PropTypes.func.isRequired,
    charts : PropTypes.array.isRequired,
}

const mapStateToStore = state => ({
    prev : state.charts.prev,
    next : state.charts.next,
    charts : state.charts.items,
});

export default connect(mapStateToStore, { fetchAllData })(CompanyList);

如果有人能幫助我解決這個問題並理解它以防止進一步的誤導或再次發生,我將不勝感激。 謝謝你。

我注意到 fetchcall 是一個異步請求的問題之一,所以我認為 companyarray 將是有效負載中的一個空白數組。 您確定在調度 FETCH_COMPANIES 時收到 payload.companies 嗎?

您的 fetch thunk 不太正確。 特別是,這一行:

payload : FetchCall(posts),

FetchCall是異步的,但您不會在調度之前等待它完成。 FetchCall中,您將在ALL_DATA調用完成之前返回帶有空CompanyArray的 ALL_DATA。

您需要在returndispatch之前完成所有 fetch 調用。 您可以使用Promise / then來執行此操作,但我發現使用async / await更容易。 無論哪種方式,您都需要Promise.all來解析整個陣列。 (另外我不知道你為什么在一個地方使用axios並在另一個地方fetch ?)。

// helper function to fetch the data for one company
const getCompanyData = (symbol) => {
  const res = await axios.get(`https://API/${symbol}/`);
  return {
    name: symbol,
    data: res.data,
  }
}

export const fetchAllData = (url) => async (dispatch) => {
  const res = await axios.get(url);
  const posts = res.data;
  const {next, prev, results} = posts;

  const companyArray = await Promise.all(
    results.map( element => getCompanyData(element.symbol) )
  );

  dispatch({
    type : FETCH_COMPANIES,
    payload: {
      next,
      prev,
      companyArray,
    }
  });
}

暫無
暫無

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

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