如何在 Next.js 和 App-Router 中使用 Redux Toolkit?

huangapple go评论65阅读模式
英文:

How to use Redux Toolkit with Next.js and App-Router?

问题

这是Redux Toolkit在NextJS 13应用程序路由中的使用示例。以下是与Redux Toolkit相关的所有切片和代码。请注意,这里不包括完整的代码,只提供了关键部分的翻译:

  1. apiSlice.js:API切片的定义,用于与后端通信。

  2. usersApiSlice.js:用户API切片的定义,包括登录、注册和注销等功能。

  3. authSlice.js:身份验证切片的定义,包括设置凭据和注销等功能。

  4. provider.js:React Redux提供程序的定义,用于在整个应用程序中提供Redux存储。

  5. store.js:Redux存储的配置,包括authReducer和API切片的中间件。

  6. layout.js:应用程序的布局组件,包括提供Redux存储和头部。

  7. login/page.jsx:登录页面的定义,包括表单处理和与Redux存储的交互。

如果您有关于特定部分的问题或需要更多详细信息,请提出具体问题。

英文:

How to use Redux toolkit in NextJS 13 App router ?

These are all my slices and code related to redux toolkit Is there anything wrong with the code coz I get this error in terminal saying , I think In Nextjs 13 we have to create a seperate provider like I did but I don't know what the error please help me find the error:

apiSlice.js:


import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";

const baseQuery = fetchBaseQuery({
  baseUrl: "http://localhost:8000/",
  credentials: "include",
});

export const apiSlice = createApi({
  baseQuery,
  tagTypes: ["User"],
  endpoints: (builder) => ({}),
});

usersApiSlice.js:

import { apiSlice } from "./apiSlice";
const USERS_URL = "http://localhost:8000/api/users";

export const usersApiSlice = apiSlice.injectEndpoints({
  endpoints: (builder) => ({
    login: builder.mutation({
      query: (data) => ({
        url: `${USERS_URL}/auth`,
        method: "POST",
        body: data,
      }),
    }),
    register: builder.mutation({
      query: (data) => ({
        url: `${USERS_URL}`,
        method: "POST",
        body: data,
      }),
    }),
    logout: builder.mutation({
      query: () => ({
        url: `${USERS_URL}/logout`,
        method: "POST",
      }),
    }),
  }),
});

export const { useLoginMutation, useLogoutMutation, useRegisterMutation } =
  usersApiSlice;

authSlice.js :

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

const initialState = {
  userInfo: null,
};

const authSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    setCredentials: (state, action) => {
      state.userInfo = action.payload;
      localStorage.setItem("userInfo", JSON.stringify(action.payload));
    },
    logout: (state, action) => {
      state.userInfo = null;
      localStorage.removeItem("userInfo");
    },
  },
});

export default authSlice.reducer;
export const { setCredentials, logout } = authSlice.actions;

provider.js:

"use client";

import { Provider } from "react-redux";
import { store } from "./store";

export function Providers({ children }) {
  return <Provider store={store}>{children}</Provider>;
}

export default Providers;

store.js :

import { configureStore } from "@reduxjs/toolkit";
import authReducer from "./features/auth/authSlice";
import { apiSlice } from "./features/api/apiSlice";

export const store = configureStore({
  reducer: {
    auth: authReducer,
    [apiSlice.reducerPath]: apiSlice.reducer,
  },
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware().concat(apiSlice.middleware),
  devTools: true,
});

layout.js:

"use client";
import "./globals.css";
import { Providers } from "./GlobalRedux/provider";
// import { ToastContainer } from "react-toastify";
// import "react-toastify/dist/ReactToastify.css";

import { Inter } from "next/font/google";
import Header from "./components/Header";
import { Provider } from "react-redux";
import { store } from "./GlobalRedux/store";

const inter = Inter({ subsets: ["latin"] });

export const metadata = {
  title: "Create Next App",
  description: "Generated by create next app",
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <Provider store={store}>
          <Header />
          {children}
        </Provider>
      </body>
    </html>
  );
}

login/page.jsx :

"use client";
import { useState, useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { useLoginMutation } from "@/app/GlobalRedux/features/api/usersApiSlice";
import { setCredentials } from "@/app/GlobalRedux/features/auth/authSlice";
import { useRouter } from "next/navigation";
// import { toast } from "react-toastify";
import styles from "../loginregister.module.css";

const page = () => {
  const router = useRouter();

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const dispatch = useDispatch();

  const [login, { isLoading, error }] = useLoginMutation();

  const { userInfo } = useSelector((state) => state.auth);

  useEffect(() => {
    if (userInfo) {
      router.push("/");
    }
  }, [router, userInfo]);

  const submitHandler = async (e) => {
    e.preventDefault();
    try {
      const res = await login({ email, password });
      dispatch(setCredentials({ ...res }));
      if (res.data.status === 201) {
        router.push("/");
      }
    } catch (err) {
      alert(err?.data?.message || err.error);
      // toast.error(err?.data?.message || err.error);
    }
  };

  return (
    <div className={styles.form}>
      <h1>Login</h1>

      <form onSubmit={submitHandler}>
        <input
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          type="email"
          name="email"
          placeholder="Email"
        />
        <input
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          type="password"
          name="password"
          placeholder="Password"
        />
        {isLoading && <h2>Loading...</h2>}
        <button>Login</button>
      </form>
    </div>
  );
};

export default page;

答案1

得分: 2

Here are the translated parts of the provided code:

In JSX or TSX:

import { Provider } from "react-redux";
import { store } from "./store";
import React from "react";

export default function ReduxProvider({ children }: { children: React.ReactNode }) {
    return <Provider store={store}>{children}</Provider>;
};

In your Layout:

import './globals.css';
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import ReduxProvider from "@/app/store/ReduxProvider";

const inter = Inter({ subsets: ['latin'] });

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={inter.className}>
        <ReduxProvider>
          {children}
        </ReduxProvider>
      </body>
    </html>
  );
}

Please note that I've converted the HTML-like tags back to their JSX/TSX equivalents for clarity.

英文:

Create à ReduxProvider in jsx or tsx :

&quot;use client&quot;;
import {Provider} from &quot;react-redux&quot;
import {store} from &quot;./store&quot;;
import React from &quot;react&quot;;

export default function ReduxProvider({children}: { children: React.ReactNode }) {
    return &lt;Provider store={store}&gt;{children}&lt;/Provider&gt;;
};

And in your Layout :

import &#39;./globals.css&#39;
import type { Metadata } from &#39;next&#39;
import { Inter } from &#39;next/font/google&#39;
import ReduxProvider from &quot;@/app/store/ReduxProvider&quot;;

const inter = Inter({ subsets: [&#39;latin&#39;] })

export const metadata: Metadata = {
  title: &#39;Create Next App&#39;,
  description: &#39;Generated by create next app&#39;,
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body className={inter.className}&gt;
      &lt;ReduxProvider&gt;
        {children}
      &lt;/ReduxProvider&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  )
}

答案2

得分: 1

我通过在进行数据请求的组件中添加'use client'来解决了这个问题。由于Redux只在客户端初始化,因此服务器组件(没有'use client'头部的组件)无法使用RTK。

英文:

I solved this problem by adding 'use client' to the component in which I was making a data request via RTK Query. Since Redux is initialized only on the client, server components (components without the 'use client' header) cannot use RTK.

答案3

得分: 0

你已经创建了你的Providers文件和组件,但没有在使用它。

export default function RootLayout({ children }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body className={inter.className}&gt;
        &lt;Providers&gt;
          &lt;Header /&gt;
          {children}
        &lt;/Providers&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}
英文:

You have created your Providers file and component, but are not using it.

export default function RootLayout({ children }) {
  return (
    &lt;html lang=&quot;en&quot;&gt;
      &lt;body className={inter.className}&gt;
        &lt;Providers&gt;
          &lt;Header /&gt;
          {children}
        &lt;/Providers&gt;
      &lt;/body&gt;
    &lt;/html&gt;
  );
}

huangapple
  • 本文由 发表于 2023年5月22日 00:41:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/76300929.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定