#背景と実施したこと
next.jsにおけるコンポーネント間の値の受け渡し、およびJSXにおける繰り返し処理を実装してみたので
備忘として残します。
#目次
- 概要
- ナビゲーションメニューに配列を使う
- 「Each child in a list should have a unique "key" prop」 の解消
##概要
- ヘッダーメニューを作る際は配列を用いてJSXを活かした実装にしよう。
- jsxにはfor文はないので、mapを使って「繰り返し」を実装しよう。
- mapを使用する際は「key」を指定して警告を解除しよう。
##ナビゲーションメニューに配列を使う
以下の画像のようなヘッダーメニューを作るときにはメニューの中身を直接HTMLに記載するより
js上の配列に格納しておく方が、保守性の観点からも望ましいでしょう。
(せっかくnext.js,Reactを使っているならJSX記法も活用した方がいい)
ということで、もともとは以下のような実装だったものをJSXを活用したものに変更していきます。
■変更前
export default function Header() {
}
return (
<nav className='flex'>
<div className='flex-none sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
<Link href='/'>
<a>
<Image src='/images/logo.png' alt='logo' width={200} height={100} />
</a>
</Link>
</div>
<div className='flex-initial text-[#abc5c5] font-bold m-5'>
<ul className='md:flex hidden flex-initial text-left'>
<li className='p-4'>
<button className='font-bold'>about</button>
</li>
<li className='p-4'>
<button className='font-bold'>skills</button>
</li>
<li className='p-4'>
<button className='font-bold'>values</button>
</li>
<li className='p-4'>
<button className='font-bold'>future</button>
</li>
</ul>
</div>
</nav>
###親コンポーネントから値を渡す
今回はHeaderコンポーネントを呼び出す親コンポーネントに配列を持たせました。
これは別にHeaderコンポーネントの中にあっても問題ないと思うのですが、(というかヘッダーの情報はヘッダーに集約した方が本来的にはよいはず)
コンポーネント間の値の受け渡しの確認もしたかったので、そういう実装にしています。
menuListという配列の各要素にnameというキーをもたせて連想配列を格納しています。
キーがnameしかないので連想配列でなくてもよいのですが、何かしらのキーの追加が今後あるかもしれないのでこうしています。
そしてHeaderコンポーネントを呼び出す部分で、listという名称にmenuListを入れて、子コンポーネントに渡します。
export default function Layouut() {
const menuList = [
{ name: 'about' },
{ name: 'skills'},
{ name: 'values'},
{ name: 'future'}
];
return (
<>
<Header list={menuList}></Header>
<main>
<Main />
<About />
<Skill />
<Values />
<Future />
</main>
<Footer />
</>
);
}
###子コンポーネント側で親からもらった値を参照する
子コンポーネント側ではpropsという引数を指定しており、
dataというconstの引数に一度格納しています。
ulタグの中でJSX記法によってdataを活用します。
「リストの要素の数だけメニューを表示する」という繰り返しを実現するためにはmap関数を活用します。
※for文は使えない
これで配列の要素の数だけメニューを表示することはできます。
export default function Header(props) {
const data = props.list;
return (
<nav className='flex'>
<div className='flex-none sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
<Link href='/'>
<a>
<Image src='/images/logo.png' alt='logo' width={200} height={100} />
</a>
</Link>
</div>
<div className='flex-initial text-[#abc5c5] font-bold m-5'>
<ul className='md:flex hidden flex-initial text-left'>
{data.map((value) => (
<li className='p-4'>
<button className='font-bold'>{value.name}</button>
</li>
))}
</ul>
</div>
</nav>
);
}
「Each child in a list should have a unique "key" prop」 の解消
これはリストの中身が削除や追加などの変更があった際に、どの項目が変わったかを判断するためにkey(配列の要素の何番目か)という情報を入れることを推奨しているからです。
そのためコードを以下のように変更します。
※mapの第2引数にindexを付与して、liタグの中にkeyを指定しています。
これで警告は消えます。
export default function Header(props) {
const data = props.list;
return (
<nav className='flex'>
<div className='flex-none sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
<Link href='/'>
<a>
<Image src='/images/logo.png' alt='logo' width={200} height={100} />
</a>
</Link>
</div>
<div className='flex-initial text-[#abc5c5] font-bold m-5'>
<ul className='md:flex hidden flex-initial text-left'>
{data.map((value, index) => (
<li key={index} className='p-4'>
<button className='font-bold'>{value.name}</button>
</li>
))}
</ul>
</div>
</nav>
);
}
##まとめ
変更前と変更後を比べてみるとコードがすっきりしたことがわかりますね。
■Before
export default function Header() {
}
return (
<nav className='flex'>
<div className='flex-none sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
<Link href='/'>
<a>
<Image src='/images/logo.png' alt='logo' width={200} height={100} />
</a>
</Link>
</div>
<div className='flex-initial text-[#abc5c5] font-bold m-5'>
<ul className='md:flex hidden flex-initial text-left'>
<li className='p-4'>
<button className='font-bold'>about</button>
</li>
<li className='p-4'>
<button className='font-bold'>skills</button>
</li>
<li className='p-4'>
<button className='font-bold'>values</button>
</li>
<li className='p-4'>
<button className='font-bold'>future</button>
</li>
</ul>
</div>
</nav>
■After
export default function Header(props) {
const data = props.list;
return (
<nav className='flex'>
<div className='flex-none sm:flex-1 md:flex-1 lg:flex-1 xl:flex-1'>
<Link href='/'>
<a>
<Image src='/images/logo.png' alt='logo' width={200} height={100} />
</a>
</Link>
</div>
<div className='flex-initial text-[#abc5c5] font-bold m-5'>
<ul className='md:flex hidden flex-initial text-left'>
{data.map((value, index) => (
<li key={index} className='p-4'>
<button className='font-bold'>{value.name}</button>
</li>
))}
</ul>
</div>
</nav>
);
}
今回はメニューということで動的になることはないと思いますが、配列などの変数を活用してHTMLを作っていくのは動的なサイトを実現したい場合は必須のテクニックです。
繰り返しの要素がある場合はmapを使う、ということと合わせて覚えていきましょう。