i'm trying to learn react along with using store. What im trying to do is having 2 components (one main and child) I want to call API for data in main component and pass this data to child component and then render this data in react-chartjs-2 component.
This is my main component (Home.tsx) which calls API for UserData (I receive data from back-end properly as array [].
import React, { useEffect, useState } from "react";
import { History } from "history";
import { connect } from "react-redux";
import { ApplicationState } from "../../store";
import { actionCreators, reducer } from "../../store/auth";
import axios from 'axios';
import 'antd/dist/antd.css'
import { Card, Button } from 'antd';
import BalanceChart from "./child-components/BalanceChart";
type HomeProps = ReturnType<typeof reducer>
& typeof actionCreators
& { readonly history: History };
const Home: React.FC<HomeProps> = ({
id,
historicalBalanceValues
}) => {
const [balanceValue, setBalanceValue] = React.useState([]);
const getUserRequest = async () => {
let response = await axios({
url: `https://localhost:44340/api/users/${id}`,
method: 'get'
});
return response.data;
};
useEffect(() => {
id = sessionStorage.getItem("userId");
getUserRequest()
.then(data => {
setBalanceValue(data.item.balanceValue);
if (!!data.item.historicalBalances){
historicalBalanceValues = data.item.historicalBalances.map(r => r.balanceValue);
}
});
});
return (
<div >
<h1 className='home-header'>Savings</h1>
<div className='card-container'>
<Card style={{ width: 400, marginLeft: '75px' }} title={'Total balance'}>
<div className='balance-container'>
<div className='balance-value'>{balanceValue}</div>
<Button className='goal-button' type='primary' shape='round'>Add goal</Button>
</div>
</Card>
<Card style={{ width: 400, marginLeft: '75px'}} title={'Balance trend'}>
<BalanceChart chartData={historicalBalanceValues}></BalanceChart>
</Card>
</div>
</div>
);
};
const mapStateToProps = (state: ApplicationState) => ({
id: state.auth.id
});
export default connect(mapStateToProps, actionCreators)(Home);
And this is my second component in which I want to display Line Chart using data I have passed from Home component.
import React, { Component } from 'react';
import { Line } from 'react-chartjs-2';
import axios from 'axios';
import PasswordInput from "../../Login/child-components/PasswordInput";
type BalanceChartState = {
balanceChartData: []
}
let chartOptionsData = {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: 'Label',
data: this.props.chartData,
backgroundColor: [
'rgba(255, 99, 132, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
],
borderWidth: 1
}]
};
export class BalanceChart extends Component<{chartData: any}, BalanceChartState> {
componentDidMount() {
this.setState({balanceChartData: this.props.chartData})
}
render() {
const { balanceChartData } = this.state;
return (balanceChartData && balanceChartData.length) ?
<Line data={chartOptionsData}></Line> : <Line data={[0]}></Line>
}
}
export default BalanceChart;
The problem is that data I'm passing from one component to the other one is 'undefined'. I think that API call for data happens after the components are rendered, however I don't know how can I achieve this. I want to pass data once components are rendered. I would like to know what is a good practice to achieve this. Thanks
asyn, so your child component will be rendered with initial value of data. You have 2 options, either you can conditionally render your child component if it has the data from API call or in your child component, check for data, ifnull, return<></>