I am trying to implement a dashboard where in I have couple of items that needs to be shown . In the following example I have 4 rectangular boxes(In actual those are 4 different graphs) and a table. I am using react-table for the data grid purposes and a semantic-ui-react table for the spinner purposes.
Now the issue is , these all are independent of each other. I have mocked the data using a settimeout as if it were coming from the back-end. All I need is individual loaders and it should be hidden whenever data arrives. 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. For mock purposes, I have used setTimeout
Could go for individual flags for each item, but that does not seems a good approach.
Mock Sandbox: https://codesandbox.io/s/react-table-row-table-vdnfh
import * as React from "react";
import { render } from "react-dom";
import "./styles.css";
import Card from "./Card";
interface IProps {}
interface IState {
cardData1: any;
cardData2: any;
cardData3: any;
cardData4: any;
}
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();
}
// the reason why I call this four times is because, in my case the API is same for all the graphs, only an attribute changes so just mocking it here
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="Card3"
data={this.state.cardData4}
spinnerFlag={cardData4 === undefined}
/>
</>
);
}
}
render(<App />, document.getElementById("root"));
When using the absolutely positioned element import { Dimmer } from "semantic-ui-react"
, and do not wish to have 4 overlapping elements over the whole page, you need to give them a relatively positions parent, e.g.:
.box {
position: relative;
}
https://codesandbox.io/s/react-table-row-table-et7ie
If you need to distinguish between empty card and the API returns ""
for an empty card, then the initial state needs to be different from that value, e.g.:
this.state = {
cardData1: undefined,
cardData2: undefined,
cardData3: undefined,
cardData4: undefined
};
and then check for that initial value:
<Card
name="Card1"
data={this.state.cardData1}
spinnerFlag={this.state.cardData1 === undefined}
/>