LoginSignup
22
15

More than 3 years have passed since last update.

ReactとパンくずリストとContextAPI

Last updated at Posted at 2019-12-08

この記事は React Advent Calendar 2019 の 9日目の記事です。

パンくずリストを ContextAPI で実装したら、使い方の勉強になったので実装方法をまとめました。

Next.js でデモを実装しているので、他の環境で利用する場合は少し置き換えが必要ですが、基本部分は変更せずに再利用可能です。

t-yng/react-breadcrumb-example

デモ
Edit react-breadcrumb-demo

目次

パンくずリストコンポーネントの作成

コンポーネントの描画イメージです

スクリーンショット 2019-12-08 18.53.46.png

reduce() で渡されたパンくずリストの要素の一覧を セパレーター(>) で結合をしています。

Linkコンポーネントは Next.js 依存なので、ここだけ自分の環境で適宜置き換えてください。


import React, { FC } from 'react';
import Link from 'next/link';

export interface BreadcrumbItem {
    id: number;
    text: string;
    href?: string;
}

interface BreadcrumbProps {
    items: BreadcrumbItem[];
    separator?: string;
}

const Breadcrumb: FC<BreadcrumbProps> = ({ items, separator = '>' }) => {
    return (
        <>
            {
                items
                .map(item =>
                    item.href != null
                        // next/link を利用しているので、環境に合わせて書き換えが必要
                        ? <Link href={item.href}>{item.text}</Link>
                        : <span>{item.text}</span>
                )
                .reduce((prev, curr) => prev.length === 0 ? [curr] : [...prev, ` ${separator} `, curr], [])
            }
        </>
    )
}

export default Breadcrumb;

Contextの作成

パンくずリストの一覧を設定するための setBreadcrumbItems() を定義した BreadcrumbContext を作成します。
ここではインターフェースを定義しているだけで、中身の実装は次の BreadcrumbProvider で行なっていきます。


import React from 'react';
import { BreadcrumbItem } from './Breadcrumb';

interface BreadcrumbContext {
    setBreadcrumbItems: (items: BreadcrumbItem[]) => void;
}

export const BreadcrumbContext = React.createContext({} as BreadcrumbContext);

Providerの作成

上で作成したコンポーネントとContextを組み合わせてパンくずリストを表示する機能を提供するコンポーネントです。

データの流れとしては

  1. 子コンポーネントが渡された BreadcrumbContextsetBredcrumbItems() にパンくずリストの一覧を指定して呼び出す
  2. ここで定義されている setBreadcrumbItems() が実行され items の一覧が更新される
  3. Breadcrumb コンポーネントに更新された items が渡されてパンくずリストが描画される

となります。

ページ遷移での描画が残るのを防ぐために、ページ遷移のイベントに合わせて一覧を初期化しています。
next/routerを利用しているので、環境に合わせて書き換えてください。

import React, { useState, FC, HTMLAttributes, useEffect } from 'react';
import { useRouter } from 'next/router';
import { BreadcrumbContext } from './BreadcrumbContext';
import Breadcrumb, { BreadcrumbItem } from './Breadcrumb';

export const BreadcrumbProvider: FC<HTMLAttributes<HTMLElement>> = ({
    children,
}) => {
    const router = useRouter();
    const [items, setItems] = useState([] as BreadcrumbItem[]);

    // ページ遷移をした時にパンくずリストを初期化する
    useEffect(() => {
        // next/router を利用しているので、環境に合わせて書き換えが必要
        router.events.on('routeChangeComplete', () => setItems([]));
    }, []);

    const setBreadcrumbItems = (_items: BreadcrumbItem[]) => {
        // コンポーネントの再帰的な描画を防ぐために空の時だけセットする
        if (items.length === 0) {
            setItems(_items);
        }
    };

    return (
        <>
            <BreadcrumbContext.Provider value={{ setBreadcrumbItems }}>
                {<Breadcrumb items={items} />}
                {children}
            </BreadcrumbContext.Provider>
        </>
    );
};

Hooks関数の作成

useContext()をラップした関数を作成します。
子コンポーネントは BreadcrumbContext を直接参照せずに、この関数を経由してContextを利用します。

useContext()を直接呼び出しても問題が無いですが、利用側が中の実装を意識する必要があり気持ち悪いのと、contextの取得後に何か処理を追加したい時に取り回しやすくなるので、面倒がらずにラップしておくことをオススメします。


import { useContext } from 'react';
import { BreadcrumbContext } from './BreadcrumbContext';
import { BreadcrumbItem } from './Breadcrumb';

export const useBreadcrumb = (items: BreadcrumbItem[]) => {
    const context = useContext(BreadcrumbContext);
    context.setBreadcrumbItems(items);
};

使い方

ルートコンポーネント


export const RootComponent = ({children}) => (
    <BreadcrumbProvider>
        {children}
    </BreadcrumbProvider>
)

子孫コンポーネント


export const ChildComponent = {
    useBreadcrumb([
        {
            id: 1,
            text: 'Home',
            href: '/'
        },
        {
            id: 2,
            text: 'About',
        }
    ]);

    return <h1>This is About Page</h1>
}

参考

schiehll/react-alert

22
15
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
22
15