【NextJS】Hooks-useContext・useReducer

1. 概要

前回はCheckbox・Radio・Select扱う内容についてでした。今回はHooksのuseContextとuseReducerを使いコンポネント間で値を共有する内容となります。

対象としては開発を1年程やってて自分で最初から開発してみたい方になります。そのため細かい用語などの説明はしません。

2. nodeのインストール

こちらを参考

3. プロジェクトを作成

こちらを参考

4. 必要なライブラリをインストール

こちらを参考

5. ソースコード

※前回より差分のみを記載

5-1-1. src/app/hooks/hook05/page.module.scss

.component {
  color: blue;
  & ul {
    margin-left: 20px;
    & li {
      list-style: disc;
    }
  }
}

5-1-2. src/app/hooks/hook05/counter-provider.tsx

import { createContext, Context, useContext, useReducer } from "react";

const CounterWatchContext: Context<number> = createContext(0);
const CounterUpdateContext: Context<any> = createContext(0);

export type Action = {
  symbol: string;
  step?: number;
};

export const CounterProvider = ({ children }: any) => {
  const reducer = (state: number, action: Action): number => {
    const { symbol, step = 1 } = action;
    switch (symbol) {
      case "+":
        return state + step;
      case "-":
        return state - step;
      default:
        return state;
    }
  };
  const [count, dispatch] = useReducer(reducer, 0);
  return (
    <CounterWatchContext.Provider value={count}>
      <CounterUpdateContext.Provider value={dispatch}>
        {children}
      </CounterUpdateContext.Provider>
    </CounterWatchContext.Provider>
  );
};

export const useWatchCounter = () => useContext(CounterWatchContext);
export const useUpdateCounter = () => useContext(CounterUpdateContext);

5-1-3. src/app/hooks/hook05/grandchild.tsx

import Box from "@mui/material/Box";
import { useWatchCounter } from "./counter-provider";

const Grandchild = () => {
  const count = useWatchCounter();
  return (
    <>
      <Box
        sx={{
          width: "100%",
          p: 2,
          border: "1px dashed grey",
          borderRadius: "20px",
          backgroundColor: "cyan",
          "&:hover": {
            backgroundColor: "white",
            opacity: [0.9, 0.8, 0.7],
          },
        }}
      >
        Grandchild({count})
      </Box>
    </>
  );
};

export default Grandchild;

5-1-4. src/app/hooks/hook05/child.tsx

import Box from "@mui/material/Box";
import Grandchild from "./grandchild";
import { useWatchCounter } from "./counter-provider";

const Child = () => {
  const count = useWatchCounter();
  return (
    <>
      <Box
        sx={{
          width: "100%",
          p: 2,
          border: "1px dashed grey",
          borderRadius: "20px",
          backgroundColor: "yellow",
          "&:hover": {
            backgroundColor: "white",
            opacity: [0.9, 0.8, 0.7],
          },
        }}
      >
        Child({count})
        <Grandchild />
      </Box>
    </>
  );
};

export default Child;

5-1-5. src/app/hooks/hook05/myself.tsx

import { Button, Stack } from "@mui/material";
import Box from "@mui/material/Box";
import scss from "./page.module.scss";
import GoBack from "@/lib/components/go-back";
import { useWatchCounter, useUpdateCounter, Action } from "./counter-provider";
import Child from "./child";

const Myself = () => {
  const count = useWatchCounter();
  const dispatch = useUpdateCounter();
  const countUpDown = (action: Action) => {
    dispatch(action);
  };
  return (
    <div className={scss.component}>
      <GoBack />
      <br />
      <br />
      <ul>
        <li>Updating the screen</li>
        <ul>
          <li>Sharing data between components</li>
        </ul>
      </ul>
      <br />
      <Box
        sx={{
          width: "100%",
          p: 2,
          border: "1px dashed grey",
          borderRadius: "20px",
          backgroundColor: "orange",
          "&:hover": {
            backgroundColor: "white",
            opacity: [0.9, 0.8, 0.7],
          },
        }}
      >
        Myself({count})
        <Child />
      </Box>
      <br />
      <ul>
        <li>Check the sharing data (Click below button)</li>
      </ul>
      <br />
      <Stack spacing={1} sx={{ width: "50%" }}>
        <Button
          variant="contained"
          size="medium"
          color="primary"
          onClick={() => countUpDown({ symbol: "+", step: 3 })}
        >
          + 3 ({count})
        </Button>
        <Button
          variant="contained"
          size="medium"
          color="secondary"
          onClick={() => countUpDown({ symbol: "-" })}
        >
          - 1 ({count})
        </Button>
      </Stack>
    </div>
  );
};

export default Myself;

5-1-6. src/app/hooks/hook05/page.tsx

"use client";

import { CounterProvider } from "./counter-provider";
import Myself from "./myself";

const Hook05 = () => {
  return (
    <CounterProvider>
      <Myself />
    </CounterProvider>
  );
};

export default Hook05;

5-1-7. src/app/hooks/page.tsx

"use client";

import React from "react";
import { Link } from "@mui/material";

import scss from "./page.module.scss";

const Hooks = () => {
  return (
    <div className={scss.components}>
      <ul>
        <li>
          <Link href="/hooks/hook01" underline="hover">
            Hook01
          </Link>
        </li>
        <li>
          <Link href="/hooks/hook02" underline="hover">
            Hook02
          </Link>
        </li>
        <li>
          <Link href="/hooks/hook03" underline="hover">
            Hook03
          </Link>
        </li>
        <li>
          <Link href="/hooks/hook04" underline="hover">
            Hook04
          </Link>
        </li>
        <li>
          <Link href="/hooks/hook05" underline="hover">
            Hook05
          </Link>
        </li>
      </ul>
    </div>
  );
};

export default Hooks;

6. サーバーを起動

npm run dev

7. ブラウザで確認

  • http://localhost:3000

8. ディレクトリの構造

.
├── README.md
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
│   ├── next.svg
│   └── vercel.svg
├── src
│   ├── app
│   │   ├── components
│   │   │   ├── component01
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── component02
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── component03
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── component04
│   │   │   │   ├── checkbox-demo.tsx
│   │   │   │   ├── page.module.scss
│   │   │   │   ├── page.tsx
│   │   │   │   ├── radio-demo.tsx
│   │   │   │   └── select-demo.tsx
│   │   │   ├── page.module.scss
│   │   │   └── page.tsx
│   │   ├── events
│   │   │   ├── event01
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── page.module.scss
│   │   │   └── page.tsx
│   │   ├── favicon.ico
│   │   ├── globals.css
│   │   ├── globals.scss
│   │   ├── hooks
│   │   │   ├── hook01
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── hook02
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── hook03
│   │   │   │   ├── child.tsx
│   │   │   │   ├── counter-provider.tsx
│   │   │   │   ├── grandchild.tsx
│   │   │   │   ├── myself.tsx
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── hook04
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── hook05
│   │   │   │   ├── child.tsx
│   │   │   │   ├── counter-provider.tsx
│   │   │   │   ├── grandchild.tsx
│   │   │   │   ├── myself.tsx
│   │   │   │   ├── page.module.scss
│   │   │   │   └── page.tsx
│   │   │   ├── page.module.scss
│   │   │   └── page.tsx
│   │   ├── layout.module.scss
│   │   ├── layout.tsx
│   │   ├── page.module.scss
│   │   └── page.tsx
│   ├── lib
│   │   ├── common
│   │   │   ├── definitions.ts
│   │   │   └── sidebar-links.tsx
│   │   ├── components
│   │   │   ├── alert-snackbar.tsx
│   │   │   ├── go-back.tsx
│   │   │   └── spacer.tsx
│   │   ├── footer.tsx
│   │   ├── header.tsx
│   │   ├── sidebar.tsx
│   │   └── utils
│   │       └── util.ts
│   └── scss
│       └── common
│           ├── _index.scss
│           ├── _mixin.scss
│           ├── _mq.scss
│           └── _variables.scss
├── tailwind.config.ts
└── tsconfig.json

22 directories, 67 files

9. 備考

今回はHooksのuseContextとuseReducerを使いコンポネント間で値を共有する内容でした。

10. 参考

投稿者プロフィール

Sondon
開発好きなシステムエンジニアです。
卓球にハマってます。

関連記事

  1. 【NextJS】OAuth authentication with A…

  2. 【NextJS】SnackbarやLink

  3. 【NextJS】Dynamic Routes

  4. 【NextJS】SassとTypescriptでレイアウトを構成

  5. 【NextJS】Canvasを使い、図形を描画

  6. 【NextJS】OAuth authentication with G…

最近の記事

  1. AWS
  2. AWS
  3. AWS
  4. AWS
  5. AWS

制作実績一覧

  1. Checkeys