今回作成するもの
このようなよくあるAlertBoxのcomponentを作成していきます。
最近はcssフレームワークで簡単に部品を提供してくれていますが、現場によっては自分で作成していく部分も多々あります!
目標としてはただ作るだけではなく、なるべく綺麗に保守性の高いコードを意識していきます。
前提知識
- React, Next.jsの基礎
- Componentの理解
- TypeScriptの基礎
対象
- React初学者
- バックエンドをメインにやっているがフロントエンドも触りたい
早速やってみよう!
今回はNext.js, TypeScript, Sassを使用しcssはcss moduleベースで書いていきます。
ルートディレクトリにcomponentディレクトリを作成し、AlertBoxディレクトリを作成します。
AlertBoxディレクトリの中に
- AlertBox.tsx
- AlertBox.module.scss
を作成しましょう。
ちなみにSassは
npm install --save sass
でインストールしておきましょう。
ではさくっと完成系のコードを載せてから説明していきます。
import React, {memo, useState, VFC} from "react";
import styled from "./AlertBox.module.scss";
type AlertProps = {
title: string;
description: string;
alertType: "ERROR" | "INFO" | "WARNING" | "SUCCESS"
}
export const AlertBox: VFC<AlertProps> = memo((props) => {
const { title, description, alertType } = props;
const [closeAlertBox, setCloseAlertBox] = useState<boolean>(true);
const alertTypeModifierCSS_Class = (): string | null => {
switch (alertType) {
case "ERROR": return styled.alertBox__Error;
case "INFO": return styled.alertBox__Info;
case "WARNING": return styled.alertBox__Warning;
case "SUCCESS": return styled.alertBox__Success;
default: return null;
}
}
const onclickCloseAlertBox = (): void => {
setCloseAlertBox(!closeAlertBox)
}
return (
<>
{closeAlertBox &&
<div className={`${alertTypeModifierCSS_Class()} ${styled.alertBox}`}>
<div className={styled.alertBody}>
<div className={styled.alertTitle}>{ title }</div>
<div className={styled.alertDescription}>{ description }</div>
</div>
<div className={styled.closeButton}></div>
<span
className={styled.closeButton}
onClick={onclickCloseAlertBox}
>{ '×' }</span>
</div>
}
</>
);
});
まずは上からReactをインポートし、memo, useState, VFCをインポートし(後で説明します)、styleをインポートしておきましょう。
これでスタイルが読み込めます。
styledは任意の名前なのでなんでもおっけいです!
自分はstyledにしています。
classesとかにしているものよくみますね。
propsの型定義
type AlertProps = {
title: string;
description: string;
alertType: "ERROR" | "INFO" | "WARNING" | "SUCCESS"
}
ここでまずpropsの型を宣言しています。
AlertBoxのタイトルと説明、そして今回は4つのタイプを作成していくので
- error(エラー)
- info(お知らせ)
- warning(警告)
- success(成功)
基本的にこの4パターンで構成されることが多いと思うのでこちらで行っていきます!
export const AlertBox: VFC<AlertProps> = memo((props) => {}
こちらはAlertBoxをFunctional Componentで定義しています。
Functional Componentの型定義はVFCで行います。
これは 一番上のReactからimponetしていますね。
FCはFunctional Componentの略で、VFCはFCの強化版程度に思っていてください。
VFC<AlertProps>
これで先ほど定義した型をpropsに設定しています。
memo
Reactで結構やりがちなのが無駄なサイレンダリングが起きてしまうことです。
サイレンダリングが起きれば起きるほどページの速度は遅くなります。
サイレンダリングが起きる条件は大きく3つあります。
- stateが更新された時
- propsの値が更新された時
- Componentがサイレンダリングされた際のComponent配下の子要素
問題はこちらです。
”Componentがサイレンダリングされた際のComponent配下の子要素”
つまりAlertBoxが使われているComponentがサイレンダリングされるとAlertBoxもサイレンダリングされてしまうということです、、、
これは避けたいですね。
memoで囲んであげるとこれを解決することができます!
const { title, description, alertType } = props;
こちらでpropsをまとめています。
本来は{ props.title }などと書かなければですが、こちらで{ title }だけで済むようになります。
state 部分
const [closeAlertBox, setCloseAlertBox] = useState<boolean>(true);
こちらでstateを管理しています。
今回はAlertBoxを削除する×ボタンを配置しているので、真偽知を設定しています.
useStateで型を設定していますが、こちらは型推論もあるので書かなくても問題はないです。
ただ自分の経験上型推論に頼ると、型定義しなければいけないところで怠っているケースを多々みてきたので、基本的に全て型定義するようにしています。
このあたりは現場ではチームのルールに従って書くのが良いと思います!!
先にreturn配下のJSX部分をみていきます!
return (
<>
{closeAlertBox &&
<div className={`${alertTypeModifierCSS_Class()} ${styled.alertBox}`}>
<div className={styled.alertBody}>
<div className={styled.alertTitle}>{ title }</div>
<div className={styled.alertDescription}>{ description }</div>
</div>
<div className={styled.closeButton}></div>
<span
className={styled.closeButton}
onClick={onclickCloseAlertBox}
>{ '×' }</span>
</div>
}
</>
);
{closeAlertBox && 左辺がtrueならば右を返す}
という意味です。
const [closeAlertBox, setCloseAlertBox] = useState<boolean>(true);
closeAlertBoxはstateで初期値をtrueに設定してあるので、初めは表示されますね!
<span
className={styled.closeButton}
onClick={onclickCloseAlertBox}
>{ '×' }</span>
この×ボタンのところでクリックイベントを使ってtrue, falseを変えています!
const onclickCloseAlertBox = (): void => {
setCloseAlertBox(!closeAlertBox)
}
クリックされるとイベントが発火しsetCloseAlertBoxの処理が行われます!
こちらでfalseになるのでAlertBoxの表示が消えます!!
switch文で4種類に分ける
実務に入る前はswitch分ってどんな時に使うんだろうって思っていたんですが、かなり使えます。
今回は4種類に定義していきたいのでswitch分でクラスを指定し、styleを変えていきます!
const alertTypeModifierCSS_Class = (): string | null => {
switch (alertType) {
case "ERROR": return styled.alertBox__Error;
case "INFO": return styled.alertBox__Info;
case "WARNING": return styled.alertBox__Warning;
case "SUCCESS": return styled.alertBox__Success;
default: return null;
}
}
何も選択されなかった場合を想定してdefaultをnullで返しています。
なので型も
string |(または) null
ですね。
ちなみにcss moduleで二つのクラスを定義する場合はこう書きます。
<div className={`${alertTypeModifierCSS_Class()} ${styled.alertBox}`}>
alertTypeModifierCSS_Class()を指定することでpropsで渡ってくる値によってstyleを変更します。
スタイリング
// - Type別のスタイル ====================== //
.alertBox__Error {
background: #FFE1E0;
color: #D81E00;
}
.alertBox__Info {
background: #E0F7FF;
color: #075C99;
}
.alertBox__Warning {
background: #FFF0D6;
color: #F5A623;
}
.alertBox__Success {
background: #E5FEE0;
color: #339F69;
}
// - 共通スタイル ====================== //
.alertBox {
display: flex;
width: 610px;
height: 97px;
.alertBody {
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 60px;
}
.alertTitle {
font-size: 18px;
font-weight: bold;
}
.alertDescription {
padding-top: 14px;
font-size: 14px;
}
.closeButton {
margin-top: 10px;
margin-right: 10px;
margin-left: auto;
cursor: pointer;
}
}
こんな感じです!
先ほどswitch文で定義したクラスをこちらでそれぞれ振り当て、背景色、文字色を変えています!
// - Type別のスタイル ====================== //
.alertBox__Error {
background: #FFE1E0;
color: #D81E00;
}
.alertBox__Info {
background: #E0F7FF;
color: #075C99;
}
.alertBox__Warning {
background: #FFF0D6;
color: #F5A623;
}
.alertBox__Success {
background: #E5FEE0;
color: #339F69;
}
ではこちらで完成したので、みていきましょう!!
import {AlertBox} from "../components/orfanism/alertBox/AlertBox";
export default function Home() {
return (
<div>
<AlertBox
title={"エラー重要なメッセージ"}
description={"エラーについての文章が入ります。エラーについての文章が入ります。"}
alertType={"ERROR"}
/>
<AlertBox
title={"お知らせのメッセージ"}
description={"お知らせについての文章が入ります。お知らせについての文章が入ります。"}
alertType={"INFO"}
/>
<AlertBox
title={"警告のメッセージ"}
description={"警告についての文章が入ります。警告についての文章が入ります。"}
alertType={"WARNING"}
/>
<AlertBox
title={"成功のメッセージ"}
description={"成功についての文章が入ります。成功についての文章が入ります。"}
alertType={"SUCCESS"}
/>
</div>
);
};
あとは自分でスタイルの変更などアレンジしてみましょう!
お疲れさまでした!!
# 完成系のコード
ごちゃごちゃしないように最後に完成系のコードを載せておきます。
import React, {memo, useState, VFC} from "react";
import styled from "./AlertBox.module.scss";
type AlertProps = {
title: string;
description: string;
alertType: "ERROR" | "INFO" | "WARNING" | "SUCCESS"
}
export const AlertBox: VFC<AlertProps> = memo((props) => {
const { title, description, alertType } = props;
const [closeAlertBox, setCloseAlertBox] = useState<boolean>(true);
const alertTypeModifierCSS_Class = (): string | null => {
switch (alertType) {
case "ERROR": return styled.alertBox__Error;
case "INFO": return styled.alertBox__Info;
case "WARNING": return styled.alertBox__Warning;
case "SUCCESS": return styled.alertBox__Success;
default: return null;
}
}
const onclickCloseAlertBox = (): void => {
setCloseAlertBox(!closeAlertBox)
}
return (
<>
{closeAlertBox &&
<div className={`${alertTypeModifierCSS_Class()} ${styled.alertBox}`}>
<div className={styled.alertBody}>
<div className={styled.alertTitle}>{ title }</div>
<div className={styled.alertDescription}>{ description }</div>
</div>
<div className={styled.closeButton}></div>
<span
className={styled.closeButton}
onClick={onclickCloseAlertBox}
>{ '×' }</span>
</div>
}
</>
);
});
// - Type別のスタイル ====================== //
.alertBox__Error {
background: #FFE1E0;
color: #D81E00;
}
.alertBox__Info {
background: #E0F7FF;
color: #075C99;
}
.alertBox__Warning {
background: #FFF0D6;
color: #F5A623;
}
.alertBox__Success {
background: #E5FEE0;
color: #339F69;
}
// - 共通スタイル ====================== //
.alertBox {
display: flex;
width: 610px;
height: 97px;
.alertBody {
display: flex;
flex-direction: column;
justify-content: center;
padding-left: 60px;
}
.alertTitle {
font-size: 18px;
font-weight: bold;
}
.alertDescription {
padding-top: 14px;
font-size: 14px;
}
.closeButton {
margin-top: 10px;
margin-right: 10px;
margin-left: auto;
cursor: pointer;
}
}