Description
My use case
I need to select the state of a slice that may not have been injected yet (returning either undefined
, the initial state, or the current state). To handle the initial state if it has been injected but no action has been fired yet, I use rootReducer.selector
(as per https://redux-toolkit.js.org/api/combineSlices#selector). This does indeed return the result of initialState()
.
The problem
However, initialState()
is called again every time the selector is called, causing a new state object to be created every time. This in turn causes useSelector
to log the "Selector unknown returned a different result when called with the same parameters." warning.
Desired behavior
I would expect the result of initialState()
to be memoized by the library.
Though perhaps I'm overlooking a case where you would want the initial state to be recreated (maybe when the same slice is mounted in multiple stores?). If so, it would be nice to update the documentation for createSlice#initialState
to inform the user they might want to memoize the result themselves?
Reproducible case
See this CodePen for the reproducible case:
import {
combineSlices,
createSlice,
configureStore
} from "https://esm.sh/@reduxjs/toolkit";
// Set up simple reducer & store.
const rootReducer = combineSlices();
const store = configureStore({ reducer: rootReducer });
// Build `selectTest` using rootReducer, instead of using injectedTestSlice/withTestSlice,
// so it can be used outside of the code-split slice module (weird use case, I know).
const selectTest = rootReducer.selector((rootState) => rootState.test);
console.log(selectTest(store.getState())); // undefined, as expected
// Set up test slice, with functional `initialState` and incrementing `counter` to highlight
// initial state being recreated.
let counter = 0;
const testSlice = createSlice({
name: "test",
initialState: () => ({
counter: counter++
})
});
testSlice.injectInto(rootReducer);
console.log(selectTest(store.getState())); // { counter: 2 }, expected { counter: 0 }
console.log(selectTest(store.getState())); // { counter: 3 }, expected { counter: 0 }