😇

Next.js14, TypeScriptでReduxを使用する際のテーマカラーの切り替え

2024/05/29に公開

Reactでreduxを実装するようにやったら沼った件

そういえばNext.js, TypeScriptでRedux実装したことなかったなぁと、素のreactで実装するノリでやってみたらファイルの置き場所間違ってるし、必要なファイル作成してないしで、まあ沼る、沼る(笑)

公式を探したら普通にあったので秒で解決した件

https://redux.js.org/usage/nextjs

完成リポジトリ
https://github.com/Kroro1208/redux-toolkit-practice

準備

Redux install

npm i @reduxjs/toolkit react-redux

React icon

npm i react-icons

ポイント

公式内にある各ポイントを紹介します。

その1 app/StoreProvider.tsxの作成

app/StoreProvider.tsx

'use client'
import { useRef } from 'react'
import { Provider } from 'react-redux'
import { makeStore, AppStore } from '../lib/store'

export default function StoreProvider({
  children
}: {
  children: React.ReactNode
}) {
  const storeRef = useRef<AppStore>()
  if (!storeRef.current) {
    // Create the store instance the first time this renders
    storeRef.current = makeStore()
  }

  return <Provider store={storeRef.current}>{children}</Provider>
}

その2 lib/store.tsを作成

import { configureStore } from "@reduxjs/toolkit";
import themeReducer from "../lib/features/theme/themeSlice";

export const makeStore = () => {
  return configureStore({
    reducer: {
      darkTheme: themeReducer,
    },
  });
};

export type AppStore = ReturnType<typeof makeStore>;
export type RootState = ReturnType<AppStore["getState"]>;
export type AppDispatch = AppStore["dispatch"];

その3 lib/features/theme/themeSlice.ts作成

import { createSlice } from "@reduxjs/toolkit";

type ThemeState = boolean;
const themeLocalStorage = !!localStorage.getItem("movies-theme");

const initialState: ThemeState = themeLocalStorage;

export const themeSlice = createSlice({
  name: "theme",
  initialState,
  reducers: {
    toggleTheme: (state) => {
      if (state) {
        localStorage.removeItem("movies-theme");
      } else {
        localStorage.setItem("movies-theme", "_");
      }
      return (state = !state);
    },
  },
});

export const { toggleTheme } = themeSlice.actions;
export default themeSlice.reducer;

その4 hooks/storeHook.ts作成

import { useDispatch, useSelector, useStore } from "react-redux";
import type { AppDispatch, AppStore, RootState } from "../lib/store";

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch = useDispatch.withTypes<AppDispatch>();
export const useAppSelector = useSelector.withTypes<RootState>();
export const useAppStore = useStore.withTypes<AppStore>();

その5 tailwind.configに追記

import type { Config } from "tailwindcss";

const config: Config = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx,mdx}",
    "./components/**/*.{js,ts,jsx,tsx,mdx}",
    "./app/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  darkMode: "class", // ここ追記
  theme: {
    extend: {
      backgroundImage: {
        "gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
        "gradient-conic":
          "conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
      },
    },
  },
  plugins: [],
};
export default config;

あとはHeaderコンポーネントによくあるテーマの切り替え設定を実装していくだけとなります。
※Guthubにあります。

まとめ

公式を見ていただくとわかりますが、テーマカラーの切り替え部分以外はほぼそのまんま使用してます。

チャレンジしてダメだったら公式を見よう!ということが再認識できる経験になりました。

Discussion