@@ -544,6 +544,8 @@ The same as [`addCase`](../api/createReducer#builderaddcase) for `createReducer`
544544``` ts no-transpile
545545const action = createAction (type )
546546context .addCase (action , reducer )
547+ // or
548+ context .addCase (type , reducer )
547549```
548550
549551#### ` addMatcher `
@@ -564,6 +566,12 @@ const action = createAction(type)
564566context .exposeAction (action )
565567```
566568
569+ :::caution
570+
571+ ` exposeAction ` should only be called once (at maximum) within a ` handle ` callback - the same applies to ` exposeCaseReducer ` .
572+
573+ :::
574+
567575#### ` exposeCaseReducer `
568576
569577Attaches a value to ` slice.caseReducers[reducerName] ` .
@@ -577,12 +585,12 @@ context.exposeCaseReducer(reducer)
577585Returns the initial state value for the slice. If a lazy state initializer has been provided, it will be called and a fresh value returned.
578586
579587``` ts no-transpile
580- const resetAction = createAction (type )
588+ const resetAction = createAction (type + ' /reset ' )
581589const resetReducer = () => context .getInitialState ()
582590context
583591 .addCase (resetAction , resetReducer )
584- .exposeAction (resetAction )
585- .exposeCaseReducer (resetReducer )
592+ .exposeAction ({ reset: resetAction } )
593+ .exposeCaseReducer ({ reset: resetReducer } )
586594```
587595
588596#### ` selectSlice `
@@ -602,7 +610,7 @@ const aThunk =
602610
603611The 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 ) .
604612
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.
606614
607615``` ts no-transpile
608616const reducerCreatorType = Symbol (' reducerCreatorType' )
@@ -634,9 +642,9 @@ The `ReducerCreatorEntry<Create, Exposes>` utility has two type parameters:
634642
635643The signature of the ` create ` method of the creator definition.
636644
637- :::caution ` CaseReducers ` and ` Name `
645+ :::caution ` CaseReducers `
638646
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.
640648
641649:::
642650
@@ -679,6 +687,39 @@ const batchedCreator: ReducerCreator<typeof batchedCreatorType> = {
679687
680688The 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 ` .
681689
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+
682723:::
683724
684725:::note Ensuring compatible state
@@ -752,6 +793,8 @@ In order to ensure that the definitions are correctly filtered to only include t
752793}
753794```
754795
796+ To relate back to the context methods, it should describe what you will pass to ` context.exposeAction ` from a handler.
797+
755798For example, with (a simplified version of) the ` asyncThunk ` creator:
756799
757800``` ts no-transpile
@@ -790,6 +833,8 @@ declare module '@reduxjs/toolkit' {
790833
791834Similar to ` actions ` , except for ` slice.caseReducers ` .
792835
836+ It describes what you will pass to ` context.exposeCaseReducer ` from a handler.
837+
793838For example, with the ` preparedReducer ` creator:
794839
795840``` ts no-transpile
@@ -1055,6 +1100,8 @@ const paginationCreator: ReducerCreator<typeof paginationCreatorType> = {
10551100 type: paginationCreatorType ,
10561101 create() {
10571102 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
10581105 prevPage: this .reducer ((state : PaginationState ) => {
10591106 state .page --
10601107 }),
@@ -1110,7 +1157,7 @@ declare module '@reduxjs/toolkit' {
11101157 ReducerPath extends string ,
11111158 > {
11121159 [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
11141161 State extends HistoryState <any >
11151162 ? (this : ReducerCreators <State >) => {
11161163 undo: CaseReducerDefinition <State , PayloadAction >
@@ -1162,18 +1209,22 @@ const historyCreator: ReducerCreator<typeof historyCreatorType> = {
11621209 state .past .push (historyEntry )
11631210 }
11641211 }),
1212+ // highlight-start
1213+ // here we're creating a reducer definition that our `handle` method will be called with
11651214 reset: {
11661215 _reducerDefinitionType: historyCreatorType ,
11671216 type: ' reset' ,
11681217 },
1218+ // highlight-end
11691219 }
11701220 },
11711221 handle(details , definition , context ) {
11721222 if (definition .type !== ' reset' ) {
11731223 throw new Error (' Unrecognised definition type: ' + definition .type )
11741224 }
1175- // use the normal reducer creator to create a case reducer and action creator
11761225 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
11771228 reducerCreator .handle (details , reducerCreator .create (resetReducer ), context )
11781229 },
11791230}
@@ -1250,7 +1301,7 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
12501301 reducer : CaseReducer <any , A >,
12511302 ): CaseReducer <HistoryState <any >, A > {
12521303 return (state , action ) => {
1253- const [nextState, redoPatch, undoPatch ] = produceWithPatches (
1304+ const [nextState, redoPatches, undoPatches ] = produceWithPatches (
12541305 state ,
12551306 (draft ) => {
12561307 const result = reducer (draft .present , action )
@@ -1264,8 +1315,8 @@ const undoableCreator: ReducerCreator<typeof undoableCreatorType> = {
12641315 if (undoable ) {
12651316 finalState = createNextState (finalState , (draft ) => {
12661317 draft .past .push ({
1267- undo: undoPatch ,
1268- redo: redoPatch ,
1318+ undo: undoPatches ,
1319+ redo: redoPatches ,
12691320 })
12701321 draft .future = []
12711322 })
@@ -1320,3 +1371,55 @@ const postSliceWithHistory = createAppSlice({
13201371const { undo, redo, reset, updateTitle, togglePinned } =
13211372 postSliceWithHistory .actions
13221373```
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