Warning: count(): Parameter must be an array or an object that implements Countable in /home/xs638785/agile-software.site/public_html/wp-content/plugins/rich-table-of-content/functions.php on line 490
プロジェクト作成
npx create-react-app . --template redux-typescript
モジュールのインポート
npm install axios
npm install @material-ui/core
npm install chart.js --save
mpm install react-chartjs-2
npm install react-countup
npm install react-icons
ファイルの準備
featuresの直下にcovidフォルダを作成しその中にCards、Chart、DashBoard、PieChart、SwitchCountryのフォルダを作成。
covidSlice.tsファイルの作成
APIのパスを定義
data型定義
type DATADAILY = typeof dataDaily;
State構造定義
initialState定義
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
import { RootState } from "../../app/store";
import dataDaily from "./apiDataDaily.json";
const apiUrl = "https://api.covid19api.com/total/country";
type DATADAILY = typeof dataDaily;
type covidState = {
daily: DATADAILY;
country: string;
};
const initialState: covidState = {
daily: dataDaily,
country: "Japan",
};
export const fetchAsyncGetDaily = createAsyncThunk(
"covid/getDaily",
async (country: string) => {
const { data } = await axios.get<DATADAILY>(`${apiUrl}/${country}`);
return { data: data, country: country };
}
);
const covidSlice = createSlice({
name: "covid",
initialState: initialState,
reducers: {},
extraReducers: (builder) => {
builder.addCase(fetchAsyncGetDaily.fulfilled, (state, action) => {
return {
...state,
daily: action.payload.data,
country: action.payload.country,
};
});
},
});
export const selectDaily = (state: RootState) => state.covid.daily;
export const selectCountry = (state: RootState) => state.covid.country;
export default covidSlice.reducer;
[
{
"Country": "Japan",
"CountryCode": "",
"Province": "",
"City": "",
"CityCode": "",
"Lat": "0",
"Lon": "0",
"Confirmed": 0,
"Deaths": 0,
"Recovered": 0,
"Active": 0,
"Date": "2020-01-22T00:00:00Z"
}
]
Reactコンポーネント
Cards
Cards.tsx
covidSlice.tsでエクスポートしたselectDailyを
配列の長さ-1で一番下の
import React from "react";
import styles from "./Cards.module.css";
import CountUp from "react-countup";
import { Card, CardContent, Typography, Grid } from "@material-ui/core";
import { GiHastyGrave } from "react-icons/gi";
import { MdLocalHospital } from "react-icons/md";
import { AiFillLike } from "react-icons/ai";
import { useSelector } from "react-redux";
import { selectDaily } from "../covidSlice";
const Cards: React.FC = () => {
const daily = useSelector(selectDaily);
return (
<div className={styles.container}>
<Grid container spacing={1} justify="center">
<Grid item xs={12} md={3} component={Card} className={styles.infected}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
<MdLocalHospital />
Infected persons
</Typography>
<Typography variant="h5">
<CountUp
start={0}
end={daily[daily.length - 1].Confirmed}
duration={1.5}
separator=","
/>
</Typography>
</CardContent>
</Grid>
<Grid item xs={12} md={3} component={Card} className={styles.recovered}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
<AiFillLike /> Recovered persons
</Typography>
<Typography variant="h5">
<CountUp
start={0}
end={daily[daily.length - 1].Recovered}
duration={1.5}
separator=","
/>
</Typography>
</CardContent>
</Grid>
<Grid item xs={12} md={3} component={Card} className={styles.deaths}>
<CardContent>
<Typography color="textSecondary" gutterBottom>
<GiHastyGrave />
Dead persons
</Typography>
<Typography variant="h5">
<CountUp
start={0}
end={daily[daily.length - 1].Deaths}
duration={1.5}
separator=","
/>
</Typography>
</CardContent>
</Grid>
</Grid>
</div>
);
};
export default Cards;
Cards.module.css
.container {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 10px;
}
.infected {
border-left: 5px solid #33a3ff;
border-radius: 0% !important;
margin: 2% 2% !important;
}
.recovered {
border-left: 5px solid #3cb371;
border-radius: 0% !important;
margin: 2% 2% !important;
}
.deaths {
border-left: 5px solid #ff3370;
border-radius: 0% !important;
margin: 2% 2% !important;
}
PieChart
PieChart.tsx
import React from "react";
import { Typography } from "@material-ui/core";
import { Doughnut } from "react-chartjs-2";
import { useSelector } from "react-redux";
import { selectDaily } from "../covidSlice";
const PieChart: React.FC = () => {
const daily = useSelector(selectDaily);
const motality =
(100 * daily[daily.length - 1].Deaths) / daily[daily.length - 1].Confirmed;
const pieChart = daily[0] && (
<Doughnut
data={{
labels: ["Infected", "Recovered", "Deaths"],
datasets: [
{
data: [
daily[daily.length - 1].Confirmed,
daily[daily.length - 1].Recovered,
daily[daily.length - 1].Deaths,
],
backgroundColor: [
"rgba(0, 0, 255, 0.5)",
"#008080",
"rgba(255, 0, 0, 0.5)",
],
hoverBackgroundColor: ["#36A2EB", "#3cb371", "#FF6384"],
borderColor: ["transparent", "transparent", "transparent"],
},
],
}}
options={{
legend: {
position: "bottom",
labels: {
boxWidth: 15,
},
},
}}
/>
);
return (
<>
<Typography align="center" color="textSecondary" gutterBottom>
Motarity {motality.toFixed(2)} [%]
</Typography>
{pieChart}
</>
);
};
export default PieChart;