React 需要单击两次才能呈现从 api 获取的数据
我需要双击链接到当前页面的按钮,这样我才能获取从 api 获取的数据进行呈现。我正在使用 nivo / charts 来可视化我的数据。
该组件从 api 获取公司列表,第二次获取循环遍历每个结果,为每个不同的公司获取数据。
第一次尝试时,公司列表要在父组件上获取,之后每个子组件都会发出获取请求
(parent=list of chart components, child=Company Chart)
,但在分页过程中它没有正确呈现,所以我不得不将状态提升到父组件,这次的问题是父组件在第一次点击时没有呈现,我不得不双击例如链接按钮以便父组件能够呈现。
我认为问题可能是因为 componentDidMount 操作顺序可能存在不同步,因为我确信第一次和第二次数据获取(第一次是公司获取请求和第二次不同的公司获取请求)是同时执行的,而不是一个接一个地执行。所以我转向 redux,并根据 redux 规则构建了我的应用程序。它没有解决任何问题,仍然需要双击链接才能进行渲染。
现在我觉得我需要为 api 获取过程添加一些 await/async 规则,但我不确定这是否可行,所以我真的很感激得到关于如何解决这个小问题的第二意见,因为它已经困扰了我好几个星期。
我的 Reducer:
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;
我的 Actions:
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);
如果有人能帮助我解决这个问题并理解它以防止进一步误导或再次发生,我将不胜感激。谢谢。
您的 fetch thunk 不太正确。特别是,这行:
payload : FetchCall(posts),
FetchCall
是异步的,但您不会在调度之前等待它完成。在
FetchCall
中,您将在 axios 调用完成之前返回带有空
CompanyArray
的
ALL_DATA
。
您需要在
return
或
dispatch
任何内容之前完成所有 fetch 调用。您可以使用
Promise
/
then
来执行此操作,但我发现使用
async
/
await
更容易。无论哪种方式
您都需要
Promise.all
来解析整个数组。(另外我不知道为什么您在一个地方使用
axios
而在另一个地方使用
fetch
?)。
// helper function to fetch the data for one company
const getCompanyData = async (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,
}
});
}
我注意到的一个问题是 fetchcall 是一个异步请求,所以我认为 companyarray 在有效负载中会是一个空白数组。您确定在调度 FETCH_COMPANIES 时会获取 payload.companies 吗?