@@ -544,6 +544,8 @@ The same as [`addCase`](../api/createReducer#builderaddcase) for `createReducer`
544
544
``` ts no-transpile
545
545
const action = createAction (type )
546
546
context .addCase (action , reducer )
547
+ // or
548
+ context .addCase (type , reducer )
547
549
```
548
550
549
551
#### ` addMatcher `
@@ -564,6 +566,12 @@ const action = createAction(type)
564
566
context .exposeAction (action )
565
567
```
566
568
569
+ :::caution
570
+
571
+ ` exposeAction ` should only be called once (at maximum) within a ` handle ` callback - the same applies to ` exposeCaseReducer ` .
572
+
573
+ :::
574
+
567
575
#### ` exposeCaseReducer `
568
576
569
577
Attaches a value to ` slice.caseReducers[reducerName] ` .
@@ -577,12 +585,12 @@ context.exposeCaseReducer(reducer)
577
585
Returns the initial state value for the slice. If a lazy state initializer has been provided, it will be called and a fresh value returned.
578
586
579
587
``` ts no-transpile
580
- const resetAction = createAction (type )
588
+ const resetAction = createAction (type + ' /reset ' )
581
589
const resetReducer = () => context .getInitialState ()
582
590
context
583
591
.addCase (resetAction , resetReducer )
584
- .exposeAction (resetAction )
585
- .exposeCaseReducer (resetReducer )
592
+ .exposeAction ({ reset: resetAction } )
593
+ .exposeCaseReducer ({ reset: resetReducer } )
586
594
```
587
595
588
596
#### ` selectSlice `
@@ -602,7 +610,7 @@ const aThunk =
602
610
603
611
The Typescript system for custom slice creators uses a "creator registry" system similar to the module system for [ RTK Query] ( /rtk-query/usage/customizing-create-api#creating-your-own-module ) .
604
612
605
- Creators are registered by using module augmentation to add a new key (their unique ` type ` ) to the ` SliceReducerCreators ` interface. The interface receives three type parameters ( ` State ` , ` CaseReducers ` and ` Name ` ), and each entry should use the ` ReducerCreatorEntry ` type utility.
613
+ Creators are registered by using module augmentation to add a new key (their unique ` type ` ) to the ` SliceReducerCreators ` interface. Each entry should use the ` ReducerCreatorEntry ` type utility.
606
614
607
615
``` ts no-transpile
608
616
const reducerCreatorType = Symbol (' reducerCreatorType' )
@@ -634,9 +642,9 @@ The `ReducerCreatorEntry<Create, Exposes>` utility has two type parameters:
634
642
635
643
The signature of the ` create ` method of the creator definition.
636
644
637
- :::caution ` CaseReducers ` and ` Name `
645
+ :::caution ` CaseReducers `
638
646
639
- Your ` Create ` type should not depend on the ` CaseReducers ` and ` Name ` type parameters , as these will not yet exist when the creator is being called.
647
+ Your ` Create ` type should not depend on the ` CaseReducers ` type parameter , as these will not yet exist when the creator is being called.
640
648
641
649
:::
642
650
@@ -679,6 +687,39 @@ const batchedCreator: ReducerCreator<typeof batchedCreatorType> = {
679
687
680
688
The second argument to the ` ReducerCreators ` type is a map from creator names to types, which you should supply if you're expecting to use any custom creators (anything other than ` reducer ` and ` preparedReducer ` ) within your own creator. For example, ` ReducerCreators<State, { asyncThunk: typeof asyncThunkCreator.type }> ` would allow you to call ` this.asyncThunk ` .
681
689
690
+ Alternatively, you can import the other creator's definition and use it directly.
691
+
692
+ ``` ts no-transpile
693
+ import { preparedReducerCreator } from ' @reduxjs/toolkit'
694
+
695
+ const batchedCreatorType = Symbol (' batchedCreatorType' )
696
+
697
+ declare module ' @reduxjs/toolkit' {
698
+ export interface SliceReducerCreators <
699
+ State ,
700
+ CaseReducers extends CreatorCaseReducers <State >,
701
+ Name extends string ,
702
+ ReducerPath extends string ,
703
+ > {
704
+ [batchedCreatorType ]: ReducerCreatorEntry <
705
+ <Payload >(
706
+ reducer : CaseReducer <State , PayloadAction <Payload >>,
707
+ ) => PreparedCaseReducerDefinition <
708
+ State ,
709
+ (payload : Payload ) => { payload: Payload ; meta: unknown }
710
+ >
711
+ >
712
+ }
713
+ }
714
+
715
+ const batchedCreator: ReducerCreator <typeof batchedCreatorType > = {
716
+ type: batchedCreatorType ,
717
+ create(reducer ) {
718
+ return preparedReducerCreator .create (prepareAutoBatched (), reducer )
719
+ },
720
+ }
721
+ ```
722
+
682
723
:::
683
724
684
725
:::note Ensuring compatible state
@@ -752,6 +793,8 @@ In order to ensure that the definitions are correctly filtered to only include t
752
793
}
753
794
```
754
795
796
+ To relate back to the context methods, it should describe what you will pass to ` context.exposeAction ` from a handler.
797
+
755
798
For example, with (a simplified version of) the ` asyncThunk ` creator:
756
799
757
800
``` ts no-transpile
@@ -790,6 +833,8 @@ declare module '@reduxjs/toolkit' {
790
833
791
834
Similar to ` actions ` , except for ` slice.caseReducers ` .
792
835
836
+ It describes what you will pass to ` context.exposeCaseReducer ` from a handler.
837
+
793
838
For example, with the ` preparedReducer ` creator:
794
839
795
840
``` ts no-transpile
@@ -1055,6 +1100,8 @@ const paginationCreator: ReducerCreator<typeof paginationCreatorType> = {
1055
1100
type: paginationCreatorType ,
1056
1101
create() {
1057
1102
return {
1103
+ // calling `this.reducer` assumes we'll be calling the creator as `create.paginationMethods()`
1104
+ // if we don't want this assumption, we could use `reducerCreator.create` instead
1058
1105
prevPage: this .reducer ((state : PaginationState ) => {
1059
1106
state .page --
1060
1107
}),
@@ -1110,7 +1157,7 @@ declare module '@reduxjs/toolkit' {
1110
1157
ReducerPath extends string ,
1111
1158
> {
1112
1159
[historyCreatorType ]: ReducerCreatorEntry <
1113
- // make sure the creator is only called when state is compatibleState extends HistoryState<unknown>
1160
+ // make sure the creator is only called when state is compatible
1114
1161
State extends HistoryState <any >
1115
1162
? (this : ReducerCreators <State >) => {
1116
1163
undo: CaseReducerDefinition <State , PayloadAction >
@@ -1162,18 +1209,22 @@ const historyCreator: ReducerCreator<typeof historyCreatorType> = {
1162
1209
state .past .push (historyEntry )
1163
1210
}
1164
1211
}),
1212
+ // highlight-start
1213
+ // here we're creating a reducer definition that our `handle` method will be called with
1165
1214
reset: {
1166
1215
_reducerDefinitionType: historyCreatorType ,
1167
1216
type: ' reset' ,
1168
1217
},
1218
+ // highlight-end
1169
1219
}
1170
1220
},
1171
1221
handle(details , definition , context ) {
1172
1222
if (definition .type !== ' reset' ) {
1173
1223
throw new Error (' Unrecognised definition type: ' + definition .type )
1174
1224
}
1175
- // use the normal reducer creator to create a case reducer and action creator
1176
1225
const resetReducer = () => context .getInitialState ()
1226
+ // you can call other creators' `handle` methods if needed
1227
+ // here we're reusing `reducerCreator` to get the expected behaviour of making an action creator for our reducer
1177
1228
reducerCreator .handle (details , reducerCreator .create (resetReducer ), context )
1178
1229
},
1179
1230
}
@@ -1250,7 +1301,7 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
1250
1301
reducer : CaseReducer <any , A >,
1251
1302
): CaseReducer <HistoryState <any >, A > {
1252
1303
return (state , action ) => {
1253
- const [nextState, redoPatch, undoPatch ] = produceWithPatches (
1304
+ const [nextState, redoPatches, undoPatches ] = produceWithPatches (
1254
1305
state ,
1255
1306
(draft ) => {
1256
1307
const result = reducer (draft .present , action )
@@ -1264,8 +1315,8 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
1264
1315
if (undoable ) {
1265
1316
finalState = createNextState (finalState , (draft ) => {
1266
1317
draft .past .push ({
1267
- undo: undoPatch ,
1268
- redo: redoPatch ,
1318
+ undo: undoPatches ,
1319
+ redo: redoPatches ,
1269
1320
})
1270
1321
draft .future = []
1271
1322
})
@@ -1320,3 +1371,55 @@ const postSliceWithHistory = createAppSlice({
1320
1371
const { undo, redo, reset, updateTitle, togglePinned } =
1321
1372
postSliceWithHistory .actions
1322
1373
```
1374
+
1375
+ :::tip ` history-adapter `
1376
+
1377
+ This example is a somewhat simplified version of the [ ` history-adapter ` ] ( https://www.npmjs.com/package/history-adapter ) package, which provides a ` createHistoryAdapter ` utility that can be used to add undo/redo functionality to a slice.
1378
+
1379
+ ``` ts no-transpile
1380
+ import {
1381
+ createHistoryAdapter ,
1382
+ historyMethodsCreator ,
1383
+ undoableCreatorsCreator ,
1384
+ } from ' history-adapter/redux'
1385
+
1386
+ const createAppSlice = buildCreateSlice ({
1387
+ creators: {
1388
+ historyMethods: historyMethodsCreator ,
1389
+ undoableCreators: undoableCreatorsCreator ,
1390
+ },
1391
+ })
1392
+
1393
+ const postHistoryAdapter = createHistoryAdapter <Post >({ limit: 5 })
1394
+
1395
+ const postSliceWithHistory = createAppSlice ({
1396
+ name: ' post' ,
1397
+ initialState: postHistoryAdapter .getInitialState ({
1398
+ title: ' ' ,
1399
+ pinned: false ,
1400
+ }),
1401
+ reducers : (create ) => {
1402
+ const createUndoable = create .undoableCreators (postHistoryAdapter )
1403
+ return {
1404
+ ... create .historyMethods (postHistoryAdapter ),
1405
+ updateTitle: createUndoable .preparedReducer (
1406
+ postHistoryAdapter .withPayload <string >(),
1407
+ (state , action ) => {
1408
+ state .title = action .payload
1409
+ },
1410
+ ),
1411
+ togglePinned: createUndoable .preparedReducer (
1412
+ postHistoryAdapter .withoutPayload (),
1413
+ (state , action ) => {
1414
+ state .pinned = ! state .pinned
1415
+ },
1416
+ ),
1417
+ }
1418
+ },
1419
+ })
1420
+
1421
+ const { undo, redo, reset, updateTitle, togglePinned } =
1422
+ postSliceWithHistory .actions
1423
+ ```
1424
+
1425
+ :::
0 commit comments