Skip to content

Commit 9897710

Browse files
jherrmarkerikson
authored andcommitted
Basic starting point for docs
1 parent ca71480 commit 9897710

File tree

4 files changed

+191
-2
lines changed

4 files changed

+191
-2
lines changed

docs/tutorials/nextjs.mdx

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
id: nextjs
3+
title: NextJS
4+
sidebar_label: NextJS
5+
hide_title: true
6+
---
7+
8+
 
9+
10+
# NextJS Application Tutorial
11+
12+
:::tip What You'll Learn
13+
14+
- How to set up and use Redux Toolkit with the NextJS framework
15+
16+
:::
17+
18+
:::info Prerequisites
19+
20+
- Familiarity with [ES6 syntax and features](https://www.taniarascia.com/es6-syntax-and-feature-overview/)
21+
- Knowledge of React terminology: [JSX](https://reactjs.org/docs/introducing-jsx.html), [State](https://reactjs.org/docs/state-and-lifecycle.html), [Function Components, Props](https://reactjs.org/docs/components-and-props.html), and [Hooks](https://reactjs.org/docs/hooks-intro.html)
22+
- Understanding of [Redux terms and concepts](https://redux.js.org/tutorials/fundamentals/part-2-concepts-data-flow)
23+
- Working through the [Quick strt guide](./quick-start.mdx) is recommended
24+
25+
:::
26+
27+
## Introduction
28+
29+
NextJS is a server side rendering framework for React that presents some unique challenges for using Redux properly. There are two architectures for a NextJS application; the Pages Router and the App Router. The Pages Router is the original architecture for NextJS. Using Redux with the Pages Router is well understood and handled primarily by the (next-redux-wrapper)[https://github.com/kirill-konshin/next-redux-wrapper]. This tutorial will focus on the App Router architecture as it is the new default architecture option for NextJS and it presents some unique challenges for using Redux properly.
30+
31+
### How to Read This Tutorial
32+
33+
This page assumes that you already have an exisiting NextJS application based on the App Router architecture.
34+
35+
## The App Router Architecture and Redux
36+
37+
The primary new feature of the NextJS App Router is the addition of support for React Server Components (RSCs). RSCs are a special type of React component that only renders on the server, as opposed to "client" components that render on **both** the client and the server. RSCs can be defined as `async` functions and return promises during rendering as they make async requests for data to render.
38+
39+
RSCs abilitiy to block for data means that with the App Router you no longer have `getServerSideProps` to fetch data for rendering. Any component in the tree can make asychronous requests for data. While this is very convenient it also means thats if you define global variables (like the Redux store) they will be shared across requests. This is a problem because the Redux store could be contaminated with data from other requests.
40+
41+
### Creating a Redux Store per Request
42+
43+
Following along with the (Quick-Start guide)[./quick-start.mdx] we need to make some changes to the `app/store.js` file. The first change is to move from defining store as a global to defining a `createStore` function that returns a new store for each request.
44+
45+
```ts title="src/app/store.ts"
46+
import { configureStore } from '@reduxjs/toolkit'
47+
48+
export const createStore = () =>
49+
configureStore({
50+
reducer: {},
51+
})
52+
53+
// Infer the type of createStore
54+
export type StoreType = ReturnType<typeof createStore>
55+
// Infer the `RootState` and `AppDispatch` types from the store itself
56+
export type RootState = ReturnType<StoreType['getState']>
57+
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
58+
export type AppDispatch = StoreType['dispatch']
59+
```
60+
61+
To use this new `createStore` function we need to create a new "client" component that will create the store and share it using the React-Redux `Provider` component.
62+
63+
```ts title="src/app/StoreProvider.tsx"
64+
// file: app/store.ts noEmit
65+
import { configureStore } from '@reduxjs/toolkit'
66+
67+
// highlight-start
68+
export const createStore = () =>
69+
configureStore({
70+
reducer: {},
71+
})
72+
// highlight-end
73+
74+
// Infer the type of createStore
75+
// highlight-start
76+
export type StoreType = ReturnType<typeof createStore>
77+
// highlight-end
78+
// Infer the `RootState` and `AppDispatch` types from the store itself
79+
export type RootState = ReturnType<StoreType['getState']>
80+
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
81+
export type AppDispatch = StoreType['dispatch']
82+
83+
// file: app/StoreProvider.tsx
84+
;('use client')
85+
import { useRef } from 'react'
86+
import { Provider } from 'react-redux'
87+
// highlight-start
88+
import { createStore } from './store'
89+
// highlight-end
90+
91+
export default function StoreProvider({
92+
children,
93+
}: {
94+
children: React.ReactNode
95+
}) {
96+
// highlight-start
97+
const storeRef = useRef<ReturnType<typeof createStore>>(createStore())
98+
// highlight-end
99+
100+
return <Provider store={storeRef.current}>{children}</Provider>
101+
}
102+
```
103+
104+
If you need to intialize the store with data from the parent component then define that data as a property and use an action on the slice to set the data in the store as shown below.
105+
106+
```ts title="src/app/StoreProvider.tsx"
107+
// file: features/counter/counterSlice.ts noEmit
108+
import { createSlice } from '@reduxjs/toolkit'
109+
import type { PayloadAction } from '@reduxjs/toolkit'
110+
111+
const counterSlice = createSlice({
112+
name: 'counter',
113+
initialState: {
114+
value: 0,
115+
},
116+
reducers: {
117+
setCount: (state, action: PayloadAction<number>) => {
118+
state.value = action.payload
119+
},
120+
},
121+
})
122+
123+
export const { setCount } = counterSlice.actions
124+
export default counterSlice.reducer
125+
126+
// file: app/store.ts noEmit
127+
import { configureStore } from '@reduxjs/toolkit'
128+
import counterReducer from '../features/counter/counterSlice'
129+
130+
export const createStore = () =>
131+
configureStore({
132+
reducer: {
133+
counter: counterReducer,
134+
},
135+
})
136+
137+
// Infer the type of createStore
138+
export type StoreType = ReturnType<typeof createStore>
139+
// Infer the `RootState` and `AppDispatch` types from the store itself
140+
export type RootState = ReturnType<StoreType['getState']>
141+
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
142+
export type AppDispatch = StoreType['dispatch']
143+
144+
// file: app/StoreProvider.tsx
145+
;('use client')
146+
import { useRef } from 'react'
147+
import { Provider } from 'react-redux'
148+
import { createStore } from './store'
149+
// highlight-start
150+
import { setCount } from '../features/counter/counterSlice'
151+
// highlight-end
152+
153+
export default function StoreProvider({
154+
count,
155+
children,
156+
}: {
157+
count: number
158+
children: React.ReactNode
159+
}) {
160+
const storeRef = useRef<ReturnType<typeof createStore> | null>(null)
161+
if (!storeRef.current) {
162+
storeRef.current = createStore()
163+
// highlight-start
164+
storeRef.current.dispatch(setCount(count))
165+
// highlight-end
166+
}
167+
168+
return <Provider store={storeRef.current}>{children}</Provider>
169+
}
170+
```
171+
172+
The next step is to include the `StoreProvider` in your layout component. This will ensure that the store is created for each request and that the store is not shared across requests. Use the store exactly as you would normally using the hooks provided by `react-redux`.
173+
174+
## What You've Learned
175+
176+
That was a brief overview of how to set up and use Redux Toolkit with the App Router:
177+
178+
:::tip Summary
179+
180+
- **Create a Redux store per request by using `configureStore` wrapped in a `createStore` function**
181+
- **Provide the Redux store to the React application components** using a "client" component
182+
- **Use the store as you normally would using the hooks provided in react-redux**
183+
184+
## What's Next?
185+
186+
We recommend going through [**the "Redux Essentials" and "Redux Fundamentals" tutorials in the Redux core docs**](https://redux.js.org/tutorials/index), which will give you a complete understanding of how Redux works, what Redux Toolkit does, and how to use it correctly.

docs/tutorials/overview.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ The [**Redux Toolkit Quick Start tutorial**](./quick-start.mdx) briefly shows ho
3131

3232
We also have a [**TypeScript Quick Start tutorial**](./typescript.md) that briefly shows how to set up and use TypeScript with Redux Toolkit and React-Redux.
3333

34+
If you are using NextJS we have a tutorial specific to using Redux Toolkit with NextJS [**NextJS tutorial**](./nextjs.mdx).
35+
3436
## Redux Essentials: A Real-World Example
3537

3638
The [**Redux Essentials tutorial**](https://redux.js.org/tutorials/essentials/part-1-overview-concepts) teaches you "how to use Redux the right way", using Redux Toolkit as the standard approach for writing Redux logic.

docs/tutorials/quick-start.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ hide_title: true
77

88
&nbsp;
99

10-
# Redux Toolkit Quick Start
10+
# NextJS Integration Tutorial
1111

1212
:::tip What You'll Learn
1313

website/sidebars.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
"tutorials/tutorials-overview",
1616
"tutorials/quick-start",
1717
"tutorials/typescript",
18-
"tutorials/rtk-query"
18+
"tutorials/rtk-query",
19+
"tutorials/nextjs"
1920
]
2021
},
2122
{

0 commit comments

Comments
 (0)