この記事の対象
・TypeScriptで型安全にActiveLinkを使いたい人
・Routerについて知りたい人
・コードを読む練習をしたい人
元々古くからのTechWikiのコードの改良みたいですが。
上の記事で@TK-Cさんが使い方の説明をされています。
本家はGitHubの@remy氏のJavaScriptを参照。
今回はJsのこのコードに型を付けました。
かなり単純かつ簡単で良いコードみたいなので勉強して行ってください。
関数→変数→条件分岐(同値演算子)→returnと言ったシンプルな内容です。
import { withRouter, NextRouter } from 'next/router';
import React, { ReactElement } from 'react';
import Link from 'next/link';
type Props = {
router: NextRouter;
children: ReactElement;
href: string;
activeClassName: string;
}
const ActiveLink = ({ router, children, ...props }: Props) => {
let className: string = children.props.className;
if (router.asPath === props.href) {
className = `${className} ${props.activeClassName}`;
}
return (
<Link {...props}>{React.cloneElement(children, { className })}</Link>
);
}
export default withRouter(ActiveLink);
####まずは条件分岐を見ます。
router.asPathとprops.hrefが一致するか比較されます。
一致した場合真になりif文の処理であるprops.activeClassNameをclassNameに代入する処理が行われます。
####リターン
classNameを返すことによって、activeClassNameとして動くclassNameという2個目の実体を定義することができました。
####ルーターの処理
router.pathnameは現在のページをパスとして認識しリンクの判定を識別するものです。
今のページがhrefと一致するならばアクティブリンクが作動するという仕組みです。
####Children.onlyは必要なのか?
Children.onlyは子要素を持たない場合に限定する目的で使われるメソッドです。
裏を返せばdom要素で下の階層を持つ場合エラーを返す処理です。
今回の場合Next.jsはActiveLinkでaタグをラップすることになるので不要だと言えます。
##childrenにReactElementを付ける理由
ReactElementは依存関係の系列でReactDomに継承させてる他
string | JSXElementConstructorを持ちます。
- 型について詳しく参考と公式ドキュメントをご覧ください。
もっといい書き方があったら教えてください。
##参考
"next": "^12.0.1"
"react": "^17.0.2"
"react-dom": "^17.0.2"
"eslint": "^7.32.0"
実行環境は以上となっています。
もしコードが動かない場合は教えてください。
11月5日追記
論理和を消しました。
trimメソッドを消しました。
if文を修正しました。
論理積を消しました。
Children.onlyのメソッドを変数ごと消しました。
child変数を消しました。
ダイナミックルーティング対応のためrouter.asPathに変更しました。