本記事は React best practices and patterns to reduce code - Part2 を提供元の事前許可を得たうえで翻訳したものです。
元の記事に従いタイトルに「ベストプラクティス」と含んでいますが、実際にはベストプラクティスは規模や状況によって大きく異なります。
チームの状況にあわせて参考にしていただければと思います。
=====
これは全3パート中の第2パートとなる記事です。
時間を無駄にしないために早速Reactのベストプラクティスとコード削減についてみていきましょう。まずは最も一般的な内容から始めます。
コンポーネントが子要素を持たない場合はself-closing tagする
よくないコード:
return <Component></Component>
よいコード:
return <Component />
jsx要素の中で関数を書かない
よくないコード:
return (
<div>
<button
onClick={() => {
setCount(1);
// ...
}}
>
Click
</button>
</div>
);
よいコード:
const onClick = useCallback(() => {
setCount(1);
// ...
}, [deps]);
return (
<div>
<button onClick={onClick}>Click</button>
</div>
);
同時に複数のstateを更新する場合はstateをオブジェクトにする
連続でsetState(setName
やsetCount
)を呼び出すのはやめましょう。これは不要なレンダリングを引き起こしてしまう、とても良くあるミスです。1回のみのsetState呼び出しが好ましいです。
よくないコード:
const [count, setCount] = useState(0);
const [name, setName] = useState("");
const onClick = () => {
setTimeout(() => {
setName("John");
setCount(count + 1);
}, 1000);
};
よいコード:
const [state, setState] = useState({
count: 0,
name: "",
});
const onClick = () => {
setTimeout(() => {
setState((prevState) => ({
...prevState,
name: "John",
count: prevState.count + 1,
}));
}, 1000);
};
注釈:React 18で自動バッチ機能が追加され、不要なレンダリングはReact自身によって最適化されるようになりました
コンポーネントのスタイリングにはstyled-componentsを使う。これはJSXでCSSを記述することやアプリケーション独自のCSS設定を避けるためにも役立ちます。
ただし主観による意見ですのでその点ご注意ください。
よくないコード:
return <div style={{ backgroundColor: "red" }}></div>;
よいコード:
const Container = styled.div`
background-color: ${({ theme }) => theme.colors.background};
padding: 1rem;
`;
よりよいコード:
const getPrimaryColor = ({ theme }) => theme.colors.primary;
const getDefaultColor = ({ theme }) => theme.colors.secondary;
const Button = styled.button`
background-color: ${getPrimaryColor};
color: ${getDefaultColor};
`;
注釈:themeから色やスタイルを取り出す関数を作りコンポーネントに渡します。これはコード量を減らすことに役立ちます。
class-basedなコンポーネントを辞めてfunctionalなコンポーネントを作る
よくないコード:
class Counter extends Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
this.onClick = this.onClick.bind(this);
}
onClick = () => {
this.setState({
count: this.state.count + 1,
});
};
render() {
return <button onClick>Click me</button>;
}
}
よいコード:
const Counter = () => {
const [count, setCount] = useState(0);
const onClick = () => setCount(count + 1);
return <button>Click me</button>;
};
注釈:functionalなコンポーネントは開発時間やコード量を減らすだけでなくバンドルサイズを60%近く減らす効果もあります。
React.memoで不要なレンダリングを避ける
よくないコード:
return (
<ui>
{items.map((item) => (
<Component>{item}</Component>
))}
</ui>
);
よいコード:
const MemoComponent = React.memo(Component);
return (
<ui>
{items.map((item) => (
<MemoComponent>{item}</MemoComponent>
))}
</ui>
);
注釈:ただしpropsの変化によりコンポーネントを頻繁にレンダリングする箇所ではReact.memo()
を使用しないように注意しましょう。
JSXのショートハンドを使う(booleanを渡す例)
よくないコード:
return <button disabled={true}>Submit</button>;
よいコード:
return <button disabled>Submit</button>;
if-elseの代わりに三項演算子を使う
よくないコード:
if (isLoading) {
return <div>Loading...</div>;
} else {
return <div>Data</div>;
}
よいコード:
return isLoading ? <div>Loading...</div> : <div>Data</div>;
switch文の代わりにオブジェクトを使う。(前回の記事と同様)
よくないコード:
switch (props.type) {
case "ADMIN":
return <Admin />;
case "USER":
return <User />;
default:
return <NotFound />;
}
よいコード:
const componentMap = {
ADMIN: Admin,
USER: User,
NOT_FOUND: NotFound,
};
const Component = componentMap[props.type];
return <Component />;
よりよいコード:
const componentMap = {
ADMIN: React.lazy(() => import("../components/Admin")),
USER: React.lazy(() => import("../components/User")),
NOT_FOUND: React.lazy(() => import("../components/NotFound")),
};
const Component = componentMap[props.type];
return <Component />;
複数の名前を指定したpropsよりもスプレッド構文を利用する
よくないコード:
const { name, age, role } = props;
return (
<>
<Component name={name} age={age} role={role} />
</>
);
よいコード:
return (
<>
<Component {...props} />
</>
);
文字列をコンポーネントに渡す場合は中括弧を削除する
よくないコード:
return <Component name={"John"} />;
よいコード:
return <Component name="John" />;
classNameやstyleといった値をReactのカスタムprops名にしない
よくないコード:
return (
<Component style="bordered">
);
よいコード:
return (
<Component variant="bordered">
);
divやspanなどの代わりにReactのfragmentを使用する
よくないコード:
return (
<div>
<span>{props.name}</span>
<span>{props.age}</span>
</div>
);
よいコード:
return (
<>
<span>{props.name}</span>
<span>{props.age}</span>
</>
);
if内で値を返却する場合はelseを書かない
よくないコード:
if (props.name) {
return <div>{props.name}</div>;
} else {
return <div>No name</div>;
}
よいコード:
if (props.name) {
return <div>{props.name}</div>;
}
return <div>No name</div>;
keyプロパティを指定する際にもdivやspanの代わりにReact.Fragmentを利用する
よくないコード:
return (
<container>
{list.map((item) => (
<div key={item.id}>
<SomeComponent />
<SomeAnotherComponent />
</div>
))}
</container>
);
よいコード:
return (
<>
{list.map((item) => (
<React.Fragment key={item.id}>
<SomeComponent />
<SomeAnotherComponent />
</React.Fragment>
))}
</>
);
ここまでお読みいただきありがとうございます😊
--
今後もWebフロントエンドにまつわる最新情報を発信予定です。
興味のある方はぜひ 公式Twitter をフォローしてください。