I have a page where multiple spinners needs to be shown. The spinners should be hidden whenever data arrives.
. In the example I have child components where in I have mocked the data using a settimeout as if it were coming from the back-end.
I have extracted the loader as a separate component, so that it behaves as a common loader for all the items.
Usually the API would give me array of items if present, and if not an empty array.
Have tried some approach but For all the cards, it's showing not found and then gets replaced with the content
Sandbox : https://codesandbox.io/embed/react-table-row-table-vdnfh?codemirror=1
import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
import Card from "./Card";
class App extends React.Component<IProps, IState> {
constructor(props: any) {
super(props);
this.state = {
cardData1: undefined,
cardData2: undefined,
cardData3: undefined,
cardData4: undefined
};
}
componentDidMount() {
this.getGraphData();
}
getGraphData = () => {
this.setGraphData("graph1");
this.setGraphData("graph2");
this.setGraphData("graph3");
this.setGraphData("graph4");
};
setGraphData = (cardNumber: string) => {
//based on the attribute I set the corresponding card data
if (cardNumber === "graph1") {
setTimeout(() => {
this.setState({ cardData1: [1, 2, 3] });
}, 1000);
}
if (cardNumber === "graph2") {
setTimeout(() => {
this.setState({ cardData2: [3, 4, 5] });
}, 2000);
}
if (cardNumber === "graph3") {
setTimeout(() => {
this.setState({ cardData3: [6, 7, 8] });
}, 3000);
}
if (cardNumber === "graph4") {
setTimeout(() => {
this.setState({ cardData4: [] });
}, 4000);
}
};
render() {
let { cardData1, cardData2, cardData3, cardData4 } = this.state;
return (
<>
<Card
name="Card1"
data={this.state.cardData1}
spinnerFlag={cardData1 === undefined}
/>
<Card
name="Card3"
data={this.state.cardData2}
spinnerFlag={cardData2 === undefined}
/>
<Card
name="Card3"
data={this.state.cardData3}
spinnerFlag={cardData3 === undefined}
/>
<Card
name="Card4"
data={this.state.cardData4}
spinnerFlag={cardData4 === undefined}
/>
</>
);
}
}
Ah okay now I understand. So your issue is that in your card component you are rendering both the data section (that either shows the data or not found) and the spinner at the same time. You need to check if the data is still being fetched (spinnerFlag) and conditionally render the spinner or the data based on that flag.
<div className="box">
{
this.props.spinnerFlag ? (
<Spinner spinnerFlag={this.props.spinnerFlag} />
) : (
<div>
{data && data.length ? (
data.map((val: any, index: any) => (
<span key={index}>Value : {val} </span>
))
) : (
<div>Not found</div>
)}
</div>
)
}
</div>
Edit: I meant when you initialize variable just use null
because youre actually setting the 'value'
this.state = {
cardData1: null,
cardData2: null,
cardData3: null,
cardData4: null
};
And then when you do
<Card
name="Card1"
data={this.state.cardData1}
spinnerFlag={!cardData1}
/>
The !
is an operator which basically means 'not' and will evaluate to a boolean that is the opposite of the actual variable. So if cardData1
is null
(falsey), !cardData1
will be true
. Then when data is set, it will be false.
P.S Fun trick, !!
forces things to a boolean if you need a boolean for whatever reason