はじめに
普段は主にバックエンド側を担当していて、フロントは必要に応じて JavaScript、HTML、CSS をいじるくらい。
React はやっておいた方がいいかなと思って、三目並べのチュートリアルに取り組んだり、Udemy、インターネットの記事などを見たり。
実際やってみると React はユニークで面白いなと思いつつ、他のことを勉強していたり、今は業務でも使わないし、少し時間が経つと細かいことを忘れてしまいがち。。
それで、以下のようなことを考えました。
- 三目並べよりもっと簡易に React の練習ができるトレーニングメニューを作って、繰り返しやったら身につくのでは?
そんな思いから、朝のラジオ対応くらいの感覚でできればという意味を込めて「React 朝の体操」というの練習メニューを作ってみました。
※朝の体操シリーズ:GORM 朝の体操
対象とする人
- React に習熟したい(React の説明はしないです。自身の血・肉にしたい人を想定)
- なんでもいいから、React の基本的な機能を使ってみたい
「React 朝の体操」の練習用 Docker 環境のありか
GitHub に置きました。
ダウンロードまたはクローンして使ってください。
https://github.com/y74h1116/react-taiso
※README.md にコンテナの起動方法を記載してあります。
動作環境
Dockerが動いて、Webブラウザがあれば動くと思います。
(こちらでは Mac、WSL で動かしています。)
また、Dockerを使わなくても、オンラインの開発環境サービス、例えば CodeSandbox などでもできるのではと思っています。
React 朝の体操の内容紹介
前述の GitHub リポジトリに README.md に朝の体操メニューを記載してありますので、その内容に従ってソースコードに追加していきます。
React のデフォルト画面に追加していきます。
トレーニングなので、見た目(デザインやCSS)や変数名にはあまり気を使わずガシガシ打ち込む感じです。
- jsx を使ってみる
下記 Hello001.tsx が実装例です。(ファイル名や表示テキストに001とつけるのは、繰り返し練習する場合、2回目は 002 にすると干渉せずにファイル追加できるためです。)
+ import { FC } from "react";
+
+ export const Hello001:FC = () => {
+ return (
+ <p>hello 001</p>
+ );
+ };
Hello001 を表示するため、App.tsx の jsx に <Hello001/>
を追加します。
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
+ import { Hello001 } from './Hello001'
function App() {
const [count, setCount] = useState(0)
return (
<>
+ <Hello001/>
<div>
~以下略~
import { FC } from "react";
export const Hello001:FC = () => {
+ const style = {border: 'solid'};
return (
+ <div style={style}>
<p>hello 001</p>
+ </div>
);
};
+ import { FC, useState } from "react";
+
+ export const Hello001Text:FC = () => {
+ const [strInput, setStrInput] = useState('');
+
+ const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
+ setStrInput(event.target.value);
+ };
+
+ return (
+ <input type="text" value={strInput} onChange={onChangeHandler}/>
+ );
+ };
Hello001 に追加します。
import { FC } from "react";
+ import { Hello001Text } from "./Hello001Text";
export const Hello001:FC = () => {
const style = {border: 'solid'};
return (
<div style={style}>
<p>hello 001</p>
+ <Hello001Text/>
</div>
);
};
import { FC, useState } from "react";
+ import { FC, useReducer, useState } from "react";
export const Hello001Text:FC = () => {
const [strInput, setStrInput] = useState('');
+ const reducerFunc = (state:string, action:string) => {
+ return state + ' => ' + action;
+ };
+ const [reducerState, dispatchFunc] = useReducer(reducerFunc, strInput);
const onChangeHandler = (event: React.ChangeEvent<HTMLInputElement>) => {
setStrInput(event.target.value);
+ dispatchFunc(event.target.value);
};
return (
+ <div>
<input type="text" value={strInput} onChange={onChangeHandler}/>
+ <p>{reducerState}</p>
+ </div>
);
};
- Recoil を使う準備
RecoilRoot を追加します。
import { FC } from "react";
import { Hello001Text } from "./Hello001Text";
+ import { RecoilRoot } from "recoil";
export const Hello001:FC = () => {
const style = {border: 'solid'};
return (
<div style={style}>
<p>hello 001</p>
<Hello001Text/>
+ <RecoilRoot>
+ </RecoilRoot>
</div>
);
};
- Recoil の Atom を使ってみる
jsx を使っていないので、拡張子は .ts にしました。
キーなどもあまりこだわらず、ファイル名と一緒にしておきます。
+ import { atom } from "recoil";
+
+ export const Hello001Atom = atom({
+ key: "Hello001Atom",
+ default: 'a',
+ });
+ import { FC } from "react";
+ import { useRecoilValue } from "recoil";
+ import { Hello001Atom } from "./Hello001Atom";
+
+ export const Hello001Show:FC = () => {
+ const strAtom = useRecoilValue(Hello001Atom);
+ return (
+ <p>{strAtom}</p>
+ );
+ };
RecoilRoot の中に配置します。
import { FC } from "react";
import { Hello001Text } from "./Hello001Text";
import { RecoilRoot } from "recoil";
+ import { Hello001Show } from "./Hello001Show";
export const Hello001:FC = () => {
const style = {border: 'solid'};
return (
<div style={style}>
<p>hello 001</p>
<Hello001Text/>
<RecoilRoot>
+ <Hello001Show/>
</RecoilRoot>
</div>
);
};
+ import { FC } from "react";
+ import { useRecoilState } from "recoil";
+ import { Hello001Atom } from "./Hello001Atom";
+
+ export const Hello001Button:FC = () => {
+ const [strAtom, setStrAtom] = useRecoilState(Hello001Atom);
+
+ const onClickHandler = () => {
+ setStrAtom(strAtom + ',a');
+ };
+
+ return (
+ <button onClick={onClickHandler}>ボタン</button>
+ );
+ };
ボタンも RecoilRoot の中に配置することを忘れずに。
import { FC } from "react";
import { Hello001Text } from "./Hello001Text";
import { RecoilRoot } from "recoil";
import { Hello001Show } from "./Hello001Show";
+ import { Hello001Button } from "./Hello001Button";
export const Hello001:FC = () => {
const style = {border: 'solid'};
return (
<div style={style}>
<p>hello 001</p>
<Hello001Text/>
<RecoilRoot>
<Hello001Show/>
+ <Hello001Button/>
</RecoilRoot>
</div>
);
};
+ import { FC, useEffect } from "react";
import { useRecoilState } from "recoil";
import { Hello001Atom } from "./Hello001Atom";
export const Hello001Button:FC = () => {
const [strAtom, setStrAtom] = useRecoilState(Hello001Atom);
const onClickHandler = () => {
setStrAtom(strAtom + ',a');
};
+ useEffect(() => {
+ document.title = 'Hello001Button:' + strAtom.length.toString();
+ }, [strAtom]);
return (
<button onClick={onClickHandler}>ボタン</button>
);
};
おわりに
もし、もう一回やる場合は、初期状態に戻してもいいですし
Hello002.tsx を作って(内容は Hello001.tsx と同じ)
以下のように Hello001 の上に Hello002 を配置してもいいと思います。
(このようにすると繰り返してやってる感が出るかなと)
import { useState } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
import { Hello001 } from './Hello001'
+ import { Hello002 } from './Hello002'
function App() {
const [count, setCount] = useState(0)
return (
<>
+ <Hello002/>
<Hello001/>
<div>
~以下略~