You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+7Lines changed: 7 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -18,6 +18,13 @@ The recommended way to start new apps with React and Redux Toolkit is by using t
18
18
npx create-react-app my-app --template redux
19
19
```
20
20
21
+
Or if you are a TypeScript user, use [cra-template-redux-typescript](https://github.com/reduxjs/cra-template-redux-typescript), which is based on that template
Copy file name to clipboardExpand all lines: docs/api/createEntityAdapter.mdx
+1Lines changed: 1 addition & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -208,6 +208,7 @@ The primary content of an entity adapter is a set of generated reducer functions
208
208
-`setAll`: accepts an array of entities or an object in the shape of `Record<EntityId, T>`, and replaces the existing entity contents with the values in the array.
209
209
-`removeOne`: accepts a single entity ID value, and removes the entity with that ID if it exists.
210
210
-`removeMany`: accepts an array of entity ID values, and removes each entity with those IDs if they exist.
211
+
-`removeAll`: removes all entities from the entity state object.
211
212
-`updateOne`: accepts an "update object" containing an entity ID and an object containing one or more new field values to update inside a `changes` field, and performs a shallow update on the corresponding entity.
212
213
-`updateMany`: accepts an array of update objects, and performs shallow updates on all corresponding entities.
213
214
-`upsertOne`: accepts a single entity. If an entity with that ID exists, it will perform a shallow update and the specified fields will be merged into the existing entity, with any matching fields overwriting the existing values. If the entity does not exist, it will be added.
Now we can use the React-Redux hooks to let React components interact with the Redux store. We can read data from the store with `useSelector`, and dispatch actions using `useDispatch`. Create a `src/features/counter/Counter.js` file with a `<Counter>` component inside, then import that component into `App.js` and render it inside of `<App>`.
Copy file name to clipboardExpand all lines: docs/tutorials/typescript.md
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -49,7 +49,7 @@ Since those are types, it's safe to export them directly from your store setup f
49
49
import { configureStore } from'@reduxjs/toolkit'
50
50
// ...
51
51
52
-
const store =configureStore({
52
+
exportconst store =configureStore({
53
53
reducer: {
54
54
posts: postsReducer,
55
55
comments: commentsReducer,
@@ -67,7 +67,7 @@ export type AppDispatch = typeof store.dispatch
67
67
68
68
### Define Typed Hooks
69
69
70
-
While it's possible to import the `RootState` and `AppDispatch` types into each component, it's **better to create typed versions of the `useDispatch` and `useSelector` hooks for usage in your application**. . This is important for a couple reasons:
70
+
While it's possible to import the `RootState` and `AppDispatch` types into each component, it's **better to create typed versions of the `useDispatch` and `useSelector` hooks for usage in your application**. This is important for a couple reasons:
71
71
72
72
- For `useSelector`, it saves you the need to type `(state:RootState)` every time
73
73
- For `useDispatch`, the default `Dispatch` type does not know about thunks. In order to correctly dispatch thunks, you need to use the specific customized `AppDispatch` type from the store that includes the thunk middleware types, and use that with `useDispatch`. Adding a pre-typed `useDispatch` hook keeps you from forgetting to import `AppDispatch` where it's needed.
Copy file name to clipboardExpand all lines: docs/usage/usage-guide.md
+12-24Lines changed: 12 additions & 24 deletions
Original file line number
Diff line number
Diff line change
@@ -26,7 +26,7 @@ Every Redux app needs to configure and create a Redux store. This usually involv
26
26
- Importing or creating the root reducer function
27
27
- Setting up middleware, likely including at least one middleware to handle asynchronous logic
28
28
- Configuring the [Redux DevTools Extension](https://github.com/zalmoxisus/redux-devtools-extension)
29
-
- Possibly altering some of the logic based on whether the application is being built for development or production.
29
+
- Possibly altering some of the logic based on whether the application is being built for development or production
30
30
31
31
### Manual Store Setup
32
32
@@ -68,7 +68,7 @@ This example is readable, but the process isn't always straightforward:
68
68
69
69
`configureStore` helps with those issues by:
70
70
71
-
- Having an options object with "named" parameters, which can be easier to read.
71
+
- Having an options object with "named" parameters, which can be easier to read
72
72
- Letting you provide arrays of middleware and enhancers you want to add to the store, and calling `applyMiddleware` and `compose` for you automatically
73
73
- Enabling the Redux DevTools Extension automatically
74
74
@@ -95,6 +95,8 @@ export default store
95
95
You can also pass an object full of ["slice reducers"](https://redux.js.org/recipes/structuring-reducers/splitting-reducer-logic), and `configureStore` will call [`combineReducers`](https://redux.js.org/api/combinereducers) for you:
96
96
97
97
```js
98
+
import { configureStore } from'@reduxjs/toolkit'
99
+
// highlight-start
98
100
importusersReducerfrom'./usersReducer'
99
101
importpostsReducerfrom'./postsReducer'
100
102
@@ -104,6 +106,9 @@ const store = configureStore({
104
106
posts: postsReducer,
105
107
},
106
108
})
109
+
// highlight-end
110
+
111
+
exportdefaultstore
107
112
```
108
113
109
114
Note that this only works for one level of reducers. If you want to nest reducers, you'll need to call `combineReducers` yourself to handle the nesting.
@@ -141,7 +146,7 @@ If you provide the `middleware` argument, `configureStore` will only use whateve
141
146
[Reducers](https://redux.js.org/basics/reducers) are the most important Redux concept. A typical reducer function needs to:
142
147
143
148
- Look at the `type` field of the action object to see how it should respond
144
-
- Update its state immutably, by making copies of the parts of the state that need to change and only modifying those copies.
149
+
- Update its state immutably, by making copies of the parts of the state that need to change and only modifying those copies
145
150
146
151
While you can [use any conditional logic you want](https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/#switch-statements) in a reducer, the most common approach is a `switch` statement, because it's a straightforward way to handle multiple possible values for a single field. However, many people don't like switch statements. The Redux docs show an example of [writing a function that acts as a lookup table based on action types](https://redux.js.org/recipes/reducing-boilerplate#generating-reducers), but leave it up to users to customize that function themselves.
The only truly necessary part here is the reducer itself. Consider the other parts:
384
389
385
-
- We could have written the action types as inline strings in both places.
386
-
- The action creators are good, but they're not _required_ to use Redux - a component could skip supplying a `mapDispatch` argument to `connect`, and just call `this.props.dispatch({type : "CREATE_POST", payload : {id : 123, title : "Hello World"}})` itself.
390
+
- We could have written the action types as inline strings in both places
391
+
- The action creators are good, but they're not _required_ to use Redux - a component could skip supplying a `mapDispatch` argument to `connect`, and just call `this.props.dispatch({type : "CREATE_POST", payload : {id : 123, title : "Hello World"}})` itself
387
392
- The only reason we're even writing multiple files is because it's common to separate code by what it does
388
393
389
394
The ["ducks" file structure](https://github.com/erikras/ducks-modular-redux) proposes putting all of your Redux-related logic for a given slice into a single file, like this:
`createSlice` looked at all of the functions that were defined in the `reducers` field, and for every "case reducer" function provided, generates an action creator that uses the name of the reducer as the action type itself. So, the `createPost` reducer became an action type of `"posts/createPost"`, and the `createPost()` action creator will return an action with that type.
Most of the time, you'll want to define a slice, and export its action creators and reducers. The recommended way to do this is using ES6 destructuring and export syntax:
Data fetching logic for Redux typically follows a predictable pattern:
615
603
616
-
- A "start" action is dispatched before the request, to indicate that the request is in progress. This may be used to track loading state to allow skipping duplicate requests or show loading indicators in the UI.
604
+
- A "start" action is dispatched before the request to indicate that the request is in progress. This may be used to track loading state, to allow skipping duplicate requests, or show loading indicators in the UI.
617
605
- The async request is made
618
606
- Depending on the request result, the async logic dispatches either a "success" action containing the result data, or a "failure" action containing error details. The reducer logic clears the loading state in both cases, and either processes the result data from the success case, or stores the error value for potential display.
619
607
@@ -1034,7 +1022,7 @@ One of the core usage principles for Redux is that [you should not put non-seria
1034
1022
1035
1023
However, like most rules, there are exceptions. There may be occasions when you have to deal with actions that need to accept non-serializable data. This should be done very rarely and only if necessary, and these non-serializable payloads shouldn't ever make it into your application state through a reducer.
1036
1024
1037
-
The [serializability dev check middleware](../api/getDefaultMiddleware.mdx) will automatically warn anytime it detects non-serializable values in your actions or state. We encourage you to leave this middleware active to help avoid accidentally making mistakes. However, if you _do_ need to turnoff those warnings, you can customize the middleware by configuring it to ignore specific action types, or fields in actions and state:
1025
+
The [serializability dev check middleware](../api/serializabilityMiddleware.mdx) will automatically warn anytime it detects non-serializable values in your actions or state. We encourage you to leave this middleware active to help avoid accidentally making mistakes. However, if you _do_ need to turnoff those warnings, you can customize the middleware by configuring it to ignore specific action types, or fields in actions and state:
Copy file name to clipboardExpand all lines: docs/usage/usage-with-typescript.md
+17-5Lines changed: 17 additions & 5 deletions
Original file line number
Diff line number
Diff line change
@@ -38,10 +38,12 @@ The basics of using `configureStore` are shown in [TypeScript Quick Start tutori
38
38
The easiest way of getting the `State` type is to define the root reducer in advance and extract its `ReturnType`.
39
39
It is recommend to give the type a different name like `RootState` to prevent confusion, as the type name `State` is usually overused.
40
40
41
-
```typescript {3}
41
+
```typescript
42
42
import { combineReducers } from'@reduxjs/toolkit'
43
43
const rootReducer =combineReducers({})
44
+
// highlight-start
44
45
exporttypeRootState=ReturnType<typeofrootReducer>
46
+
// highlight-end
45
47
```
46
48
47
49
Alternatively, if you choose to not create a `rootReducer` yourself and instead pass the slice reducers directly to `configureStore()`, you need to slightly modify the typing to correctly infer the root reducer:
@@ -56,13 +58,15 @@ const store = configureStore({
If you want to get the `Dispatch` type from your store, you can extract it after creating the store. It is recommended to give the type a different name like `AppDispatch` to prevent confusion, as the type name `Dispatch` is usually overused. You may also find it to be more convenient to export a hook like `useAppDispatch` shown below, then using it wherever you'd call `useDispatch`.
64
68
65
-
```typescript {6}
69
+
```typescript
66
70
import { configureStore } from'@reduxjs/toolkit'
67
71
import { useDispatch } from'react-redux'
68
72
importrootReducerfrom'./rootReducer'
@@ -71,8 +75,12 @@ const store = configureStore({
71
75
reducer: rootReducer,
72
76
})
73
77
78
+
// highlight-start
74
79
exporttypeAppDispatch=typeofstore.dispatch
75
80
exportconst useAppDispatch = () =>useDispatch<AppDispatch>() // Export a hook that can be reused to resolve types
81
+
// highlight-end
82
+
83
+
exportdefaultstore
76
84
```
77
85
78
86
### Correct typings for the `Dispatch` type
@@ -83,17 +91,18 @@ As TypeScript often widens array types when combining arrays using the spread op
83
91
84
92
Also, we suggest using the callback notation for the `middleware` option to get a correctly pre-typed version of `getDefaultMiddleware` that does not require you to specify any generics by hand.
0 commit comments