React+Redux-Saga场景下带参数Reselect选择器的实现正确性验证及调用优化问询
Great question! Let's break this down step by step to clarify your options and confirm what's working correctly.
1. Can you directly call the parameterized selector in sagas?
Absolutely! Your proposed syntax yield select((state) => makeGetPerson(state, id)) is fully valid and recommended.
Your current makeGetPerson selector follows Reselect's official pattern for parameterized selectors, and it works identically whether used in useSelector (components) or the select saga effect. The select effect accepts any function that takes the Redux state as input, so passing an inline function that invokes your selector with the required id is perfectly acceptable.
This approach is better than your current saga code (fetching the full list then filtering manually) because:
- It reuses the exact same selection logic everywhere, eliminating duplicate code
- If you ever update
getPersonsListor adjust the filtering logic, you only need to modifyselectors.jsonce - It keeps your saga code cleaner and aligned with your component-side state selection patterns
2. Alternative approaches to reduce saga dependency on store state
I understand your preference to avoid yield select in sagas to keep middleware decoupled from store state. Here are a few practical options to consider:
Pass required data via action payloads
Instead of fetching data from the store in the saga, pass the needed data directly when dispatching the action that triggers the saga. For example:
// In your component const person = useSelector(state => makeGetPerson(state, id)); dispatch(runPersonRelatedSaga(person)); // In your saga function* personRelatedSaga(action) { const person = action.payload; // Use person directly - no need for yield select! }
This way, the saga only depends on the action payload, not the store's internal state structure.
Use selector factory functions (optional variation)
While your current parameterized selector is correct, another common Reselect pattern is to create a factory function that returns a selector bound to a specific parameter:
// selectors.js const makeGetPerson = (id) => createSelector( getPersonsList, (persons) => persons.find(person => person.id === id) ); // Component usage const getPerson = makeGetPerson(id); const person = useSelector(getPerson); // Saga usage yield select(makeGetPerson(id));
This is functionally similar to your current setup but can feel cleaner if you have multiple parameters or want to reuse the bound selector multiple times in the same scope.
Limit saga responsibilities to side effects
Restructure your logic so sagas only handle side effects (like API calls, timers, or external integrations) and don't need to read store state at all. For example:
- If your saga needs to fetch details for a person, pass the
iddirectly in the action (instead of fetching the person from the store first) - The saga uses the
idto make the API call, then dispatches an action with the result to update the store
This keeps sagas focused on their core purpose and eliminates the need for yield select entirely.
3. Quick validation of your current selector setup
Your existing selector implementation is correct! Using Reselect with Immer is totally compatible—Immer handles immutable state updates in reducers, while Reselect caches derived state based on changes to the input selectors. There's no conflict here, and your approach follows best practices for Redux state selection.
内容的提问来源于stack exchange,提问作者lucataglia

