Loading...
(function(){<br />
let canvas = document.createElement('canvas'),<br />
ctx = canvas.getContext('2d'),<br />
w = canvas.width = innerWidth,<br />
h = canvas.height = innerHeight,<br />
particles = [],<br />
properties = {<br />
bgColor : 'rgba(17, 17, 19, 1)',<br />
particleColor : 'rgba(255, 40, 40, 1)',<br />
particleRadius : 3,<br />
particleCount : 60,<br />
particleMaxVelocity : 0.5,<br />
lineLength : 150,<br />
particleLife : 6,<br />
};<br />
<br />
document.querySelector('body').appendChild(canvas);<br />
<br />
window.onresize = function() {<br />
w = canvas.width = innerWidth;<br />
h = canvas.height = innerHeight;<br />
}<br />
<br />
class Particle {<br />
constructor() {<br />
this.x = Math.random()*w;<br />Loading...
This reference article is intended for those who already understand how Redux works. It contains only the essential information on how to integrate Redux into a Next.js application.
You need to install:
react-redux
npm i @reduxjs/toolkit react-redux
next-redux-wrapper
npm i next-redux-wrapper
Documentation: https://www.npmjs.com/package/next-redux-wrapper
react-redux
npm i react-redux
Documentation: https://react-redux.js.org/
Create slices in a lib folder. In Redux documentation, this folder is often called features, but you can name it however you prefer.
Import createSlice from @reduxjs/toolkit. If you use TypeScript, you will also need PayloadAction.
The structure of a slice in the Next.js App Router is the same as in a standard Redux setup: define initialState, actions, and selectors.
1import { createSlice, PayloadAction } from "@reduxjs/toolkit";2import { TUserDataResponse } from "@/types";34type userState = {5 userData: TUserDataResponse;6};78const initialState = {9 userData: [],10} as userState;1112export const user = createSlice({13 name: "user",14 initialState,15 reducers: {16 setUserData: (17 state,18 action: PayloadAction<TUserDataResponse>19 ) => {20 state.userData = action.payload;21 },22 },23 selectors: {24 selectUserData: (state) => {25 return state.userData;26 },27 },28});2930export const {31 setUserData32} = user.actions;33export const {34 selectUserData,35} = user.selectors;36export default user.reducer;37
Create a store file inside the lib folder. Import configureStore from Redux Toolkit and create the store.
Also import reducers from your slices.
In the example below, mainApi is an RTK Query API slice.
1import { configureStore } from "@reduxjs/toolkit";2import { mainApi } from "./mainApi"3import userReducer from "./slices/userSlice"4export const makeStore = () =>5 configureStore({6 reducer: {7 [mainApi.reducerPath]: mainApi.reducer,8 user: userReducer9 },10 middleware: (gDM) => gDM().concat(mainApi.middleware),11 });1213export type AppStore = ReturnType<typeof makeStore>;14export type RootState = ReturnType<AppStore["getState"]>;15export type AppDispatch = AppStore["dispatch"];16
In the app folder, create a file named StoreProvider (or any name you prefer). Import Provider from react-redux and makeStore and AppStore from the store.ts file.
1"use client";2import { useRef } from "react";3import { Provider } from "react-redux";4import { makeStore, AppStore } from "../lib/store";56export default function StoreProvider({7 children,8}: {9 children: React.ReactNode;10}) {11 const storeRef = useRef<AppStore>();12 if (!storeRef.current) {13 storeRef.current = makeStore();14 }1516 return <Provider store={storeRef.current}>{children}</Provider>;17}
Next, import StoreProvider into the layout.tsx file in the app folder and wrap your application components with it.
1import type { Metadata } from "next";2import { Inter } from "next/font/google";3import "./globals.css";4import { headers } from "next/headers";5import StoreProvider from "./StoreProvider";67export const runtime = "nodejs";8export const dynamic = "force-static";910const inter = Inter({ subsets: ["latin"] });1112export const metadata: Metadata = {13 title: """,14 description: "",15};1617export default function RootLayout({18 children,19}: Readonly<{20 children: React.ReactNode;21}>) {22 return (23 <html lang="en">24 <body className={`${inter.className}`}>25 <StoreProvider>26 {children}27 </StoreProvider>28 </body>29 </html>30 );31}32
Now Redux is available in your components, working just like in a standard React application.
In your component, import useDispatch from react-redux along with the action creator from your slice. In the example above, the action creator is setUserData.
1import { useDispatch } from "react-redux";2import { setUserData } from "@/lib/slices/userSlice";
Next, use dispatch to send the data to the Redux store.
1const dispatch = useDispatch();23<...>45if (apiData) {6 dispatch(setUserData(apiData));7}
In your component, import useSelector from react-redux along with the selector from your slice. In the example above, the selector is selectUserData.
1import { useSelector } from "react-redux";2import { selectUserData } from "@/lib/slices/userSlice";
Next, retrieve the data from the Redux store by calling useSelector inside your component. Pass your selector function to useSelector.
12const userData = useSelector(selectUserData);
That's it! The data is now available and ready to use in your component.
Written on July 15, 2023.
Documentation: https://redux-toolkit.js.org/api/createSlice
Create a file named after the slice of state it will represent. In this example, the file is named searchSlice.ts.
Inside the file, define the initialState and create the slice.
1import { createSlice } from "@reduxjs/toolkit";2import { AppState } from "../store";3import { HYDRATE } from "next-redux-wrapper";45// Type for our state6export interface SearchState {7 searchState: string;8}910// Initial state11const initialState: SearchState = {12 searchState: "",13};1415// Actual Slice16export const searchSlice = createSlice({17 name: "search",18 initialState,19 reducers: {20 [HYDRATE]: (state, action) => {21 return {22 ...state,23 ...action.payload,24 };25 },26 // Action to set the authentication status27 setSearchState: (state, action) => {28 state.searchState = action.payload;29 },30 },3132});3334export const { setSearchState } = searchSlice.actions;3536export const selectSearchState = (state: AppState) => state.search.searchState;3738export default searchSlice.reducer;39
HYDRATE — this is a special reducer for Next.js that works above of the existing state if it already exists.
Import your slice into store.ts. When exporting the store, wrap it using createWrapper from next-redux-wrapper.
1import { configureStore, ThunkAction, Action } from "@reduxjs/toolkit";2import { searchSlice } from "./slices/searchSlice";3import { createWrapper } from "next-redux-wrapper";45const makeStore = () =>6 configureStore({7 reducer: {8 [searchSlice.name]: searchSlice.reducer,9 },10 devTools: true,11 });1213export type AppStore = ReturnType<typeof makeStore>;14export type AppState = ReturnType<AppStore["getState"]>;15export type AppThunk<ReturnType = void> = ThunkAction<16 ReturnType,17 AppState,18 unknown,19 Action20>;2122export const wrapper = createWrapper<AppStore>(makeStore);
_app.tsxIn _app.tsx, import wrapper from store.ts and Provider from react-redux. Then, extract store and props using wrapper and pass the store instance to the Provider component.
1import { Provider } from "react-redux";2import { wrapper } from "../store/store";3import "../styles/_global.scss";45const MyApp = ({ categories, Component, ...rest }) => {6 const { store, props } = wrapper.useWrappedStore(rest);7 const { pageProps } = props;8 return (9 <Provider store={store}>10 <Component {...pageProps} />11 </Provider>12 );13};1415export default MyApp;
To update the state, use useDispatch from react-redux and import the required action creator from your slice.
To access data from the state, import the selector function from your slice and use useSelector from react-redux.