Skip to content

Commit f50d8fc

Browse files
authored
Improve Reducer Hook's lazy init API (#14723)
* Improve Reducer Hook's lazy init API * Use generic type for initilizer input Still requires an `any` cast in the case where `init` function is not provided.
1 parent fe67c16 commit f50d8fc

File tree

2 files changed

+19
-26
lines changed

2 files changed

+19
-26
lines changed

src/ReactShallowRenderer.js

+11-8
Original file line numberDiff line numberDiff line change
@@ -223,10 +223,10 @@ class ReactShallowRenderer {
223223
}
224224

225225
_createDispatcher(): DispatcherType {
226-
const useReducer = <S, A>(
226+
const useReducer = <S, I, A>(
227227
reducer: (S, A) => S,
228-
initialState: S,
229-
initialAction: A | void | null,
228+
initialArg: I,
229+
init?: I => S,
230230
): [S, Dispatch<A>] => {
231231
this._validateCurrentlyRenderingComponent();
232232
this._createWorkInProgressHook();
@@ -259,13 +259,16 @@ class ReactShallowRenderer {
259259
}
260260
return [workInProgressHook.memoizedState, dispatch];
261261
} else {
262+
let initialState;
262263
if (reducer === basicStateReducer) {
263264
// Special case for `useState`.
264-
if (typeof initialState === 'function') {
265-
initialState = initialState();
266-
}
267-
} else if (initialAction !== undefined && initialAction !== null) {
268-
initialState = reducer(initialState, initialAction);
265+
initialState =
266+
typeof initialArg === 'function'
267+
? ((initialArg: any): () => S)()
268+
: ((initialArg: any): S);
269+
} else {
270+
initialState =
271+
init !== undefined ? init(initialArg) : ((initialArg: any): S);
269272
}
270273
workInProgressHook.memoizedState = initialState;
271274
const queue: UpdateQueue<A> = (workInProgressHook.queue = {

src/__tests__/ReactShallowRendererHooks-test.js

+8-18
Original file line numberDiff line numberDiff line change
@@ -91,23 +91,19 @@ describe('ReactShallowRenderer with hooks', () => {
9191
});
9292

9393
it('should work with useReducer', () => {
94-
const initialState = {count: 0};
95-
9694
function reducer(state, action) {
9795
switch (action.type) {
98-
case 'reset':
99-
return initialState;
10096
case 'increment':
10197
return {count: state.count + 1};
10298
case 'decrement':
10399
return {count: state.count - 1};
104-
default:
105-
return state;
106100
}
107101
}
108102

109-
function SomeComponent({initialCount}) {
110-
const [state] = React.useReducer(reducer, {count: initialCount});
103+
function SomeComponent(props) {
104+
const [state] = React.useReducer(reducer, props, p => ({
105+
count: p.initialCount,
106+
}));
111107

112108
return (
113109
<div>
@@ -141,25 +137,19 @@ describe('ReactShallowRenderer with hooks', () => {
141137
});
142138

143139
it('should work with a dispatched state change for a useReducer', () => {
144-
const initialState = {count: 0};
145-
146140
function reducer(state, action) {
147141
switch (action.type) {
148-
case 'reset':
149-
return initialState;
150142
case 'increment':
151143
return {count: state.count + 1};
152144
case 'decrement':
153145
return {count: state.count - 1};
154-
default:
155-
return state;
156146
}
157147
}
158148

159-
function SomeComponent({initialCount}) {
160-
const [state, dispatch] = React.useReducer(reducer, {
161-
count: initialCount,
162-
});
149+
function SomeComponent(props) {
150+
const [state, dispatch] = React.useReducer(reducer, props, p => ({
151+
count: p.initialCount,
152+
}));
163153

164154
if (state.count === 0) {
165155
dispatch({type: 'increment'});

0 commit comments

Comments
 (0)