@@ -445,6 +445,8 @@ The same as [`addCase`](../api/createReducer#builderaddcase) for `createReducer`
445445``` ts no-transpile
446446const action = createAction (type )
447447context .addCase (action , reducer )
448+ // or
449+ context .addCase (type , reducer )
448450```
449451
450452#### ` addMatcher `
@@ -465,6 +467,12 @@ const action = createAction(type)
465467context .exposeAction (action )
466468```
467469
470+ :::caution
471+
472+ ` exposeAction ` should only be called once (at maximum) within a ` handle ` callback - the same applies to ` exposeCaseReducer ` .
473+
474+ :::
475+
468476#### ` exposeCaseReducer `
469477
470478Attaches a value to ` slice.caseReducers[reducerName] ` .
@@ -478,12 +486,12 @@ context.exposeCaseReducer(reducer)
478486Returns the initial state value for the slice. If a lazy state initializer has been provided, it will be called and a fresh value returned.
479487
480488``` ts no-transpile
481- const resetAction = createAction (type )
489+ const resetAction = createAction (type + ' /reset ' )
482490const resetReducer = () => context .getInitialState ()
483491context
484492 .addCase (resetAction , resetReducer )
485- .exposeAction (resetAction )
486- .exposeCaseReducer (resetReducer )
493+ .exposeAction ({ reset: resetAction } )
494+ .exposeCaseReducer ({ reset: resetReducer } )
487495```
488496
489497#### ` selectSlice `
@@ -503,7 +511,7 @@ const aThunk =
503511
504512The 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 ) .
505513
506- 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.
514+ 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.
507515
508516``` ts no-transpile
509517const reducerCreatorType = Symbol (' reducerCreatorType' )
@@ -535,9 +543,9 @@ The `ReducerCreatorEntry<Create, Exposes>` utility has two type parameters:
535543
536544The signature of the ` create ` method of the creator definition.
537545
538- :::caution ` CaseReducers ` and ` Name `
546+ :::caution ` CaseReducers `
539547
540- 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.
548+ Your ` Create ` type should not depend on the ` CaseReducers ` type parameter , as these will not yet exist when the creator is being called.
541549
542550:::
543551
@@ -580,6 +588,39 @@ const batchedCreator: ReducerCreator<typeof batchedCreatorType> = {
580588
581589The 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 ` .
582590
591+ Alternatively, you can import the other creator's definition and use it directly.
592+
593+ ``` ts no-transpile
594+ import { preparedReducerCreator } from ' @reduxjs/toolkit'
595+
596+ const batchedCreatorType = Symbol (' batchedCreatorType' )
597+
598+ declare module ' @reduxjs/toolkit' {
599+ export interface SliceReducerCreators <
600+ State ,
601+ CaseReducers extends CreatorCaseReducers <State >,
602+ Name extends string ,
603+ ReducerPath extends string ,
604+ > {
605+ [batchedCreatorType ]: ReducerCreatorEntry <
606+ <Payload >(
607+ reducer : CaseReducer <State , PayloadAction <Payload >>,
608+ ) => PreparedCaseReducerDefinition <
609+ State ,
610+ (payload : Payload ) => { payload: Payload ; meta: unknown }
611+ >
612+ >
613+ }
614+ }
615+
616+ const batchedCreator: ReducerCreator <typeof batchedCreatorType > = {
617+ type: batchedCreatorType ,
618+ create(reducer ) {
619+ return preparedReducerCreator .create (prepareAutoBatched (), reducer )
620+ },
621+ }
622+ ```
623+
583624:::
584625
585626:::note Ensuring compatible state
@@ -653,6 +694,8 @@ In order to ensure that the definitions are correctly filtered to only include t
653694}
654695```
655696
697+ To relate back to the context methods, it should describe what you will pass to ` context.exposeAction ` from a handler.
698+
656699For example, with (a simplified version of) the ` asyncThunk ` creator:
657700
658701``` ts no-transpile
@@ -691,6 +734,8 @@ declare module '@reduxjs/toolkit' {
691734
692735Similar to ` actions ` , except for ` slice.caseReducers ` .
693736
737+ It describes what you will pass to ` context.exposeCaseReducer ` from a handler.
738+
694739For example, with the ` preparedReducer ` creator:
695740
696741``` ts no-transpile
@@ -956,6 +1001,8 @@ const paginationCreator: ReducerCreator<typeof paginationCreatorType> = {
9561001 type: paginationCreatorType ,
9571002 create() {
9581003 return {
1004+ // calling `this.reducer` assumes we'll be calling the creator as `create.paginationMethods()`
1005+ // if we don't want this assumption, we could use `reducerCreator.create` instead
9591006 prevPage: this .reducer ((state : PaginationState ) => {
9601007 state .page --
9611008 }),
@@ -1011,7 +1058,7 @@ declare module '@reduxjs/toolkit' {
10111058 ReducerPath extends string ,
10121059 > {
10131060 [historyCreatorType ]: ReducerCreatorEntry <
1014- // make sure the creator is only called when state is compatibleState extends HistoryState<unknown>
1061+ // make sure the creator is only called when state is compatible
10151062 State extends HistoryState <any >
10161063 ? (this : ReducerCreators <State >) => {
10171064 undo: CaseReducerDefinition <State , PayloadAction >
@@ -1063,18 +1110,22 @@ const historyCreator: ReducerCreator<typeof historyCreatorType> = {
10631110 state .past .push (historyEntry )
10641111 }
10651112 }),
1113+ // highlight-start
1114+ // here we're creating a reducer definition that our `handle` method will be called with
10661115 reset: {
10671116 _reducerDefinitionType: historyCreatorType ,
10681117 type: ' reset' ,
10691118 },
1119+ // highlight-end
10701120 }
10711121 },
10721122 handle(details , definition , context ) {
10731123 if (definition .type !== ' reset' ) {
10741124 throw new Error (' Unrecognised definition type: ' + definition .type )
10751125 }
1076- // use the normal reducer creator to create a case reducer and action creator
10771126 const resetReducer = () => context .getInitialState ()
1127+ // you can call other creators' `handle` methods if needed
1128+ // here we're reusing `reducerCreator` to get the expected behaviour of making an action creator for our reducer
10781129 reducerCreator .handle (details , reducerCreator .create (resetReducer ), context )
10791130 },
10801131}
@@ -1151,7 +1202,7 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
11511202 reducer : CaseReducer <any , A >,
11521203 ): CaseReducer <HistoryState <any >, A > {
11531204 return (state , action ) => {
1154- const [nextState, redoPatch, undoPatch ] = produceWithPatches (
1205+ const [nextState, redoPatches, undoPatches ] = produceWithPatches (
11551206 state ,
11561207 (draft ) => {
11571208 const result = reducer (draft .present , action )
@@ -1165,8 +1216,8 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
11651216 if (undoable ) {
11661217 finalState = createNextState (finalState , (draft ) => {
11671218 draft .past .push ({
1168- undo: undoPatch ,
1169- redo: redoPatch ,
1219+ undo: undoPatches ,
1220+ redo: redoPatches ,
11701221 })
11711222 draft .future = []
11721223 })
@@ -1221,3 +1272,55 @@ const postSliceWithHistory = createAppSlice({
12211272const { undo, redo, reset, updateTitle, togglePinned } =
12221273 postSliceWithHistory .actions
12231274```
1275+
1276+ :::tip ` history-adapter `
1277+
1278+ 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.
1279+
1280+ ``` ts no-transpile
1281+ import {
1282+ createHistoryAdapter ,
1283+ historyMethodsCreator ,
1284+ undoableCreatorsCreator ,
1285+ } from ' history-adapter/redux'
1286+
1287+ const createAppSlice = buildCreateSlice ({
1288+ creators: {
1289+ historyMethods: historyMethodsCreator ,
1290+ undoableCreators: undoableCreatorsCreator ,
1291+ },
1292+ })
1293+
1294+ const postHistoryAdapter = createHistoryAdapter <Post >({ limit: 5 })
1295+
1296+ const postSliceWithHistory = createAppSlice ({
1297+ name: ' post' ,
1298+ initialState: postHistoryAdapter .getInitialState ({
1299+ title: ' ' ,
1300+ pinned: false ,
1301+ }),
1302+ reducers : (create ) => {
1303+ const createUndoable = create .undoableCreators (postHistoryAdapter )
1304+ return {
1305+ ... create .historyMethods (postHistoryAdapter ),
1306+ updateTitle: createUndoable .preparedReducer (
1307+ postHistoryAdapter .withPayload <string >(),
1308+ (state , action ) => {
1309+ state .title = action .payload
1310+ },
1311+ ),
1312+ togglePinned: createUndoable .preparedReducer (
1313+ postHistoryAdapter .withoutPayload (),
1314+ (state , action ) => {
1315+ state .pinned = ! state .pinned
1316+ },
1317+ ),
1318+ }
1319+ },
1320+ })
1321+
1322+ const { undo, redo, reset, updateTitle, togglePinned } =
1323+ postSliceWithHistory .actions
1324+ ```
1325+
1326+ :::
0 commit comments