初めてのAxios
はじめに
非同期処理について勉強したいと思いAxios
をバックエンド側で導入しました!(フロントエンド側ではReactを用いています。)
プロジェクトの概要
プロジェクトは一日の予定を追加、消去できるものを作成しました。スタイルは最低限に留めていて、リストの部分にはMaterial-Ui
を用いています。
ファイル構成
├── src/
├── components/
└──Reminder.tsx
└── index.tsx
└──App.tsx
└──db.json
ルートとなるApp.tsx(コードの全体)
このAppファイルは100行を超えたのでもっとコンポーネントとして分けるべきだったと反省しています。。。
ひとまず全体をお見せします。
import './App.css';
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import {
makeStyles,
Table,
TableBody,
TableContainer,
Theme,
Typography,
} from '@material-ui/core';
import useHead from './components/Reminder';
const useStyles = makeStyles((theme: Theme) => ({
table: {
marginTop: theme.spacing(3),
'& thead th': {
fontWeight: '600',
color: theme.palette.primary.main,
},
},
}));
type FormData = {
id: number;
reminder: string;
time: string;
};
export type HeadCells = {
id: number;
label: string;
}[];
const headCells: HeadCells = [
{ id: 0, label: 'id' },
{ id: 1, label: '予定' },
{ id: 2, label: '時間帯' },
];
const data: FormData = {
id: 0,
reminder: '',
time: '',
};
const App = () => {
const classes = useStyles();
const [reminder, setReminders] = useState<FormData[]>([]);
const [formData, setFormData] = useState<FormData>(data);
const axios = Axios.create({ baseURL: 'http://localhost:3000' });
const noReminder = !reminder || (reminder && reminder.length === 0);
const getReminders = async () => {
const response = await axios
.get<FormData[]>('/reminders')
.catch((err) => console.log('err:', err));
if (response && response.data) setReminders(response.data);
};
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
const addReminder = async () => {
const response = await axios
.post<FormData>('/reminders', formData)
.catch((err) => console.log('err:', err));
if (response) getReminders();
};
const deleteReminder = async (id: number) => {
const response = await axios
.delete(`/reminders/${id}`)
.catch((err) => console.log('Error deleting:', err));
if (response) await getReminders();
};
const { CardHead, Reminder } = useHead(headCells);
useEffect(() => {
getReminders();
}, []);
return (
<>
<Typography variant="h4" align="center">
今日の予定
</Typography>
{noReminder && <h2>No Reminders found!</h2>}
<TableContainer>
<Table className={classes.table}>
<CardHead />
<TableBody>
{!noReminder &&
reminder.map((reminder, id) => (
<Reminder key={id} {...reminder} onDelete={deleteReminder} />
))}
</TableBody>
</Table>
</TableContainer>
<br />
<h3>予定の追加</h3>
<form onSubmit={addReminder}>
<label htmlFor="id">Id</label>
<input name="id" placeholder="Id" onChange={handleChange} />
<label htmlFor="reminder">予定</label>
<input name="reminder" placeholder="予定" onChange={handleChange} />
<label htmlFor="time">時間帯</label>
<input name="time" placeholder="Am or Pm" onChange={handleChange} />
<button type="submit">追加</button>
</form>
</>
);
};
export default App;
コードの詳細
部分的にコードを見ていきます。
まず、createメソッドを用いていインスタンスを作成します。
const axios = Axios.create({ baseURL: 'http://localhost:3000' });
そしてデータ(id,reminder,time)はdb.json
に格納しています。JSON Serverの立ち上げ方についてはこちらの記事JSON Server使いこなしで勉強させていただきました。
このjsonファイルに追加、削除の動作をaxiosのgetメソッドとdeleteメソッドが担ってくれます。山括弧にはTypeScript
のジェネリック型を指定しています。
const getReminders = async () => {
const response = await axios
.get<FormData[]>('/reminders')
.catch((err) => console.log('err:', err));
if (response && response.data) setReminders(response.data);
};
const deleteReminder = async (id: number) => {
const response = await axios
.delete(`/reminders/${id}`)
.catch((err) => console.log('Error deleting:', err));
if (response) await getReminders();
};
getメソッドを使っているgetReminders関数ですが,レンダーの結果が画面に反映された後に動作するようにuseEffectを用いています。またuseEffecの第二引数には、依存する唯一の変数であるsetReminersを指定しています。
useEffect(() => {
getReminders();
}, [setReminders]);
次にデータを登録するためにpostメソッドを使用します。第2引数には登録するデータを渡します。
const addReminder = async () => {
const response = await axios
.post<FormData>('/reminders', formData)
.catch((err) => console.log('err:', err));
if (response) getReminders();
};
この非同期関数(addReminder)はformタグのonSubmit属性に当てており、個々のデータ(id,reminder,time)の変化はinputタグのonChange属性にhandleChange関数を割り当てています。
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
};
//JSX.Element
<form onSubmit={addReminder}>
<label htmlFor="id">Id</label>
<input name="id" placeholder="Id" onChange={handleChange} />
<label htmlFor="reminder">予定</label>
<input name="reminder" placeholder="予定" onChange={handleChange} />
<label htmlFor="time">時間帯</label>
<input name="time" placeholder="Am or Pm" onChange={handleChange} />
<button type="submit">追加</button>
</form>
</>
このhandleChange関数の作成については前々回の記事にて述べています!
フォームを作る過程でつまずいたこと
あとuseReminder関数は別ファイル(Reminder.tsx)からimportしています。
import useReminder from './components/Reminder';
const { CardHead, Reminder } = useReminder(headCells);
以下Reminder.tsxファイルの全体です。
import { Grid, TableCell, TableHead, TableRow } from '@material-ui/core';
import React from 'react';
import DeleteForeverIcon from '@material-ui/icons/DeleteForever';
import { HeadCells } from '../App';
interface Props {
id: number;
reminder: string;
time: string;
onDelete: (id: number) => any;
}
const useReminder = (headCells: HeadCells) => {
const CardHead: React.FC = () => {
return (
<TableHead>
{headCells.map(({ id, label }) => (
<TableCell key={id} align="center">
{label}
</TableCell>
))}
</TableHead>
);
};
const Reminder: React.FC<Props> = ({ id, reminder, time, onDelete }) => {
return (
<>
<TableRow key={id}>
<TableCell align="center">{id}</TableCell>
<TableCell align="center">{reminder}</TableCell>
<TableCell align="center">{time}</TableCell>
<Grid className="reminder-remove" onClick={() => onDelete(id)}>
<DeleteForeverIcon />
</Grid>
</TableRow>
</>
);
};
return { CardHead, Reminder };
};
export default useReminder;
このような子コンポーネントを一つの関数としてラップする関数(useReminder)の作成については前回記事にて述べていますので、是非御覧ください!Propsをよりスマートに渡したい!
以上、コードの詳細でした。ここまで読んでいただきありがとうございました!!
Discussion