React 需要点击两次来呈现从 api 获取的数据
React need to click twice to render data fetched from api
我需要在按钮上单击两次 linked 到当前页面,这样我才能获取从 api 获取的数据以进行呈现。我正在使用 nivo / 图表来可视化我的数据。
该组件从 api 中获取公司列表,第二次获取循环遍历每个结果以获取每个不同公司的数据。
第一次尝试时,公司列表是在父组件上获取的,此后每个子组件都会发生获取请求
(parent=list of chart components, child=Company Chart)
,但是在分页过程中没有正确渲染,所以我不得不将状态提升到父组件,这次的问题是第一次点击时父组件没有渲染,我不得不双击示例 link 按钮,以便父组件呈现。
我认为问题可能会发生,因为可能与 componentDidMount 操作顺序不同步,因为我确定第一次和第二次数据获取(第一个是公司获取请求,第二个是不同的公司获取请求) , 正在同时执行而不是一个接一个地执行。所以我指向 redux 并将我的应用程序架构为 redux 规则。它没有解决任何问题,仍然需要双击 link 才能进行渲染。
现在我觉得我需要为 api 抓取过程添加一些 await/async 规则,但我不确定这是否可行,所以我真的很感激能得到第二个关于如何解决这个小问题的意见,因为它已经困扰我几个星期了。
我的减速器:
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
中,您将在 axios 调用完成之前返回 ALL_DATA
和一个空的 CompanyArray
。
您需要在 return
ing 或 dispatch
ing 任何事情之前完成所有提取调用。您可以使用 Promise
/then
执行此操作,但我发现使用 async
/await
更容易。无论哪种方式 来解析整个数组。 (我也不知道你为什么在一个地方使用 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,
}
});
}
我需要在按钮上单击两次 linked 到当前页面,这样我才能获取从 api 获取的数据以进行呈现。我正在使用 nivo / 图表来可视化我的数据。
该组件从 api 中获取公司列表,第二次获取循环遍历每个结果以获取每个不同公司的数据。
第一次尝试时,公司列表是在父组件上获取的,此后每个子组件都会发生获取请求
(parent=list of chart components, child=Company Chart)
,但是在分页过程中没有正确渲染,所以我不得不将状态提升到父组件,这次的问题是第一次点击时父组件没有渲染,我不得不双击示例 link 按钮,以便父组件呈现。
我认为问题可能会发生,因为可能与 componentDidMount 操作顺序不同步,因为我确定第一次和第二次数据获取(第一个是公司获取请求,第二个是不同的公司获取请求) , 正在同时执行而不是一个接一个地执行。所以我指向 redux 并将我的应用程序架构为 redux 规则。它没有解决任何问题,仍然需要双击 link 才能进行渲染。
现在我觉得我需要为 api 抓取过程添加一些 await/async 规则,但我不确定这是否可行,所以我真的很感激能得到第二个关于如何解决这个小问题的意见,因为它已经困扰我几个星期了。
我的减速器:
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
中,您将在 axios 调用完成之前返回 ALL_DATA
和一个空的 CompanyArray
。
您需要在 return
ing 或 dispatch
ing 任何事情之前完成所有提取调用。您可以使用 Promise
/then
执行此操作,但我发现使用 async
/await
更容易。无论哪种方式 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,
}
});
}