So, I'm still new to redux toolkit and I'm likely doing some of this wrong. In any case, I'm curious how to extract my "selectors" from my store/slice in redux.
Let's say I have the following slice:
const mySlice = creatSlice({
name: 'my-slice',
initialState: {
stuff: {
primary: 'Things',
secondary: 'Other Things',
},
},
reducers: (create) => ({
getStuff: create.asyncThunk(
() => getSomeDataAsynchronously(),
{ ...justAssumeTheseUpdateStateWithData },
),
}),
// this is the part I'm most interested in understanding better
// I'm not even sure I'm doing it right. Is this how to handle
// using arguments, or do I need to curry or something?
selectors: {
selectStuff: (state) => state.stuff,
selectSpecificStuff: (state, key) => state[key] ?? 'not found',
}
});
const store = configureStore({
reducer: mySlice.reducer
});
So here's where I'm most confused. Let's assume I've injected that store in my Provider
, and I'm on a child react component:
import { useSelector } from 'react-redux';
const MyComponent = () => {
const selectSpecificStuff = useSelector(/* how to access from my slice? */);
return <>{selectSpecificStuff('primary')}</>;
}
Is this even possible? I can't seem to find anything about it in the docs, which makes me wonder what the point of the selectors property is, if you can't access it.
Any assistance is appreciated.
I'm curious how to extract my "selectors" from my store/slice in redux.
The selectors are extracted just like the generated actions are.
Example:
export const {
selectStuff,
selectSpecificStuff
} = myslice.selectors;
The selectSpecificStuff
selector is still working with the slice's state, so it would need to access state.stuff
first.
selectors: {
selectStuff: (state) => state.stuff,
selectSpecificStuff: (state, key) => state.stuff[key] ?? "not found"
}
or
selectors: {
selectStuff: (state) => state.stuff,
selectSpecificStuff: (state, key) => {
const stuff = mySlice.getSelectors().selectStuff(state);
return stuff[key] ?? "not found";
}
}
So here's where I'm most confused. Let's assume I've injected that store in my
Provider
, and I'm on a child react component:import { useSelector } from 'react-redux'; const MyComponent = () => { const selectSpecificStuff = useSelector(/* how to access from my slice? */); return <>{selectSpecificStuff('primary')}</>; }
Is this even possible? I can't seem to find anything about it in the docs, which makes me wonder what the point of the selectors property is, if you can't access it.
The part that initially tripped me up with these selectors is that they are generated expecting to be mounted/injected into the store using their defined reducerPath
value, which defaults to the slice's name
property by default.
Example:
import { createSlice } from '@reduxjs/toolkit';
const mySlice = createSlice({
name: 'my-slice', // <-- default reducer path
initialState: {
stuff: {
primary: 'Things',
secondary: 'Other Things',
},
},
reducers: (create) => ({
....
}),
selectors: {
selectStuff: (state) => state.stuff,
selectSpecificStuff: (state, key) => state.stuff[key] ?? "not found"
}
});
export const {
selectStuff,
selectSpecificStuff
} = myslice.selectors;
...
const store = configureStore({
reducer: {
"my-slice": mySlice.reducer // <-- mount under correct path
}
});
Import the selectors, and in the useSelector
hook callback pass the root state and the key
argument to the slice selector.
import { useSelector } from 'react-redux';
import { selectStuff, selectSpecificStuff } from '../path/to/mySlice';
const MyComponent = () => {
const stuff = useSelector(selectStuff);
const primaryStuff = useSelector((state) =>
selectSpecificStuff(state, "primary")
);
const secondaryStuff = useSelector((state) =>
selectSpecificStuff(state, "secondary")
);
const tertiaryStuff = useSelector((state) =>
selectSpecificStuff(state, "tertiary")
);
console.log({
stuff: // { stuff: { primary: "Things", secondary: "Other Things" } }
primaryStuff, // "Things"
secondaryStuff, // "Other Things"
tertiaryStuff, // "not found"
});
...
}
Using mySlice.getSelectors()
is the other way to access the selectors.
const store = configureStore({
reducer: mySlice.reducer
});
import { useSelector } from 'react-redux';
import mySlice from '../path/to/mySlice';
const MyComponent = () => {
const stuff = useSelector(mySlice.getSelectors().selectStuff);
const primaryStuff = useSelector((state) =>
mySlice.getSelectors().selectSpecificStuff(state, "primary")
);
const secondaryStuff = useSelector((state) =>
mySlice.getSelectors().selectSpecificStuff(state, "secondary")
);
const tertiaryStuff = useSelector((state) =>
mySlice.getSelectors().selectSpecificStuff(state, "tertiary")
);
console.log({
stuff: // { stuff: { primary: "Things", secondary: "Other Things" } }
primaryStuff, // "Things"
secondaryStuff, // "Other Things"
tertiaryStuff, // "not found"
});
...
}