-
Notifications
You must be signed in to change notification settings - Fork 674
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Accessing props in a composed selector's transform function #287
Comments
You can use the "factory function" form of |
@markerikson So i'm still not sure the factory function form of I need to access my argument, not in the input selectors, but rather in the transform function. How can I achieve that? Can you maybe post a code snippet solving the issue above? |
Try something like: const mapStateFactory = (originalState, originalOwnProps) => {
const isTodoItemExpandedSelector = createSelector(
getTodoItemExpansionMap,
(expansionMap) => expansionMap[originalOwnProps.instructionID]
);
return (state, ownProps) => {
return {
isExpanded : isTodoItemExpandedSelector(state)
};
}
} You could also reuse that |
@markerikson Oh I'm starting to see, but I'm having trouble finding documentation on the factory syntax for the From this I think I can deduce that the factory receives the state and props the first time around and that on subsequent renders the function that the factory returns will be used on its own. Is that correct? That would mean that the function wouldn't work right if the ID changes, right? |
Yes, that example assumes the ID being passed in as a prop isn't changing, and yes, you've understood the behavior correctly. A The factory function syntax is described in the API docs for
Which, now that I look at it, is not all that informative. We should rewrite that. |
@markerikson So, is there any way to make this work without relying on the assumption that the ID doesn't change? |
You could change the selector so that it pulls in the current ID as an input: const mapStateFactory = (originalState, originalOwnProps) => {
const isTodoItemExpandedSelector = createSelector(
[getTodoItemExpansionMap, (state, id) => id],
(expansionMap, id) => expansionMap[id]
);
return (state, ownProps) => {
return {
isExpanded : isTodoItemExpandedSelector(state, ownProps.instructionID)
};
}
} |
Oh i see! That's the technique I had been missing. So , more generally, if you need access to custom arguments in your transform function, you should make input selectors that return those arguments. Thanks |
Pretty much, yeah. It's important to note that all of the "input selectors" you provide to Here's a quick example: const selectItems = state => state.items;
const selectId = (state, id) => id;
const selectName = (state, props) => props.name;
const selectItemInfo = createSelector(
[selectItems, selectId, selectName],
(items, id, name) => {
const item = items[id];
return {
id,
name,
info : item.info
};
}
); In this case, I really need to turn that into a blog post :) |
Right so probably best practice is to pass an object containing named arguments and each input selector can deal with the ones it cares about and ignore the ones it doesn't care about. |
Yep, I'd say that's probably a safe approach. |
I filed reduxjs/react-redux#797 to cover rewriting the docs to better explain factory functions. I don't have time to do that myself right now, but if you or someone else would like to contribute, please leave a comment in that issue! |
I wrote a blog post that discusses proper use of selectors and the "factory function" syntax. If someone would like to help update the docs based on that, please let me know! Idiomatic Redux: Using Reselect Selectors for Encapsulation and Performance. |
Hopefully someone can help me here. I can't seem to find any other issues posing this exact question. (Perhaps that means my approach is wrong).
Let's say my app needs to render a list of todo items, and each TodoItem can be either expanded or collapsed. So, I have the following data structure in my redux store
My JSX might look like:
TodoItemList.jsx
TodoItem.jsx
Right now, my selectors file looks like this:
So, you can see that I'm using a factory function to generate a new selector for each ID that we will need to look at. This means my connect function would look like this:
If my logic is correct, however, this won't memoize correctly because each time the
mapStateToProps
function is called, a branch new selector will be generated via the factory.What am I missing here?
What I really want is to write the
isTodoItemExpanded
selector, not like a factory, but instead like so:The above is not possible however, unless Im missing some section of the docs.
The text was updated successfully, but these errors were encountered: