🎉

High Performance React Web 開発: Layout.tsxの解説

2022/12/04に公開

概要

下記リポジトリを参考に、typeScriptの勉強を進めているので、不明点の洗い出しと理解した内容を書き出す。解説するコードについては、末尾に記載している。
https://github.com/GomaGoma676/tanstack-react-query-rtk-lesson/blob/main/src/components/Layout.tsx

ReactNode

1行目でインポートしているReactNodeについて、様々な型を子コンポーネントで使用できる。interface Propsで、Propsが様々な型を定義できるように設定している。ただ、anyとは異なり、どんな型でも入れられる訳ではない。ReactNodeは、DOMが返す型を決めることができる。そしてここで決めた型が、Layoutに渡されている。

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

ただし、指定する型が多く、記述者の意図を伝えるために、型を絞った方が良い場合はReact
ChildやReactTextを使うと良い。

type ReactChild = ReactElement | ReactText;
type ReactText = string | number;

ReactNodeだと、stringが受け入れられない定義になっているが、ReactNodeの中にはReactTextが入っており、その中ではstringを受け入れることができる。つまり、ReactNode、ReactChild、ReactTextでstringを扱うことができる。今回の例でいえば、childrenをReactNodeではなく、ReactTextに書き換える形とすれば、stringを扱うことができる。

Props

Propsは親子関係で、親から子に同様の定義を付与する形で使われる。例えば下記の例で言うと、Layoutという関数はPropsで定義した型のみ使える関数として、子コンポーネントの定義がされている。他にも、export const Sidebar: FC Propsといった形で親コンポーネント定義→子コンポーネントのような使い方ができる。つまり、親の定義によって子コンポーネントの使用用途が一括で決められる。

export const Layout: FC<Props> 

FC

1行目でインポートしているFCについて、まず下記を例に文法を理解する。

interface GEN<T>{
  item: T
  # この時点では、GENの型がTと定義されており、定まっていない。
}
# ここでGENの型をstringと定義し、型が決まる。
const gen0: GEN<string> = {item: "hello" };
# 型をつけない場合はエラーとなる。
const gen1: GEN = {item: "hello" };
const gen2: GEN<number> = {item: 12 };

Layout

FC項目で説明の通り、TとPropsで定義の型のみ、関数内で受け取ることが可能である。Propsについては、children: ReactNodeと記述しているため、概ねの型を受け取ることが可能である。

export const Layout: FC<Props> = ({ children }) => {
  return <div>
  </div>
}

ここで使われるLayout: FCは、React独自のタグとして、別の場所で使える。この場合だと、下記に記載のとおり。実際にApp.tsxでLayoutタグが使用されている。また、returnの中身がコンポーネントの材料として作られる。例えば、Sidebarの場合は、Sidebarに必要な要素をreturnの中で定義すれば良い。

<Layout></Layout>

interface Props

下記のように定義した場合、NAMEではfirstのstringとlastのstringとnullのみ受け付ける。let nameObjでは定義した通り引数を入れているので、エラーなく処理される。もしfirst: 1といった形で、数値を入れている場合はエラーが発生する。

interface NAME {
  first: string;
  last: string | null;
}
let nameObj: NAME = { first: "Yamada", last: null }

Link

Linkは簡易的に記載すると、下記仕様で別URLへ遷移できる。

<Link to="/">Home</Link>
<Link to="/about">About</Link>
<Link to="/contact">Contact</Link>

参考文献

https://qiita.com/masash49/items/26b4c4cf316e64c2ee10
https://www.twilio.com/blog/react-choose-functional-components-jp

コード

import { ReactNode, FC } from 'react'
import { Link } from 'react-router-dom'
interface Props {
  children: ReactNode
}
export const Layout: FC<Props> = ({ children }) => {
  return (
    <div className="flex justify-center items-center flex-col min-h-screen text-gray-600 font-mono">
      <header>
        <nav className="bg-gray-800 w-screen">
            <div className="flex items-center pl-8 h-14">
                <div className="flex space-x-4">
                    <Link 
                        className="text-sm text-gray-300 hover:bg-gray-700 px-3 py-2 rounded"
                        to="/"
                    >
                        react-query
                    </Link>
                    <Link 
                        className="text-sm text-gray-300 hover:bg-gray-700 px-3 py-2 rounded"
                        to="/fetch-a"
                    >
                        Regular fetch
                    </Link>
                    <Link 
                        className="text-sm text-gray-300 hover:bg-gray-700 px-3 py-2 rounded"
                        to="/main-context"
                    >
                        useContext
                    </Link>
                    <Link 
                        className="text-sm text-gray-300 hover:bg-gray-700 px-3 py-2 rounded"
                        to="/main-rtkit"
                    >
                        RTkit
                    </Link>                    
                </div>
            </div>
        </nav>
      </header>
      <main className="flex flex-1 flex-col justify-center items-center w-screen">
        {children}
      </main>
    </div>
  )
}

Discussion