Skip to content

Instantly share code, notes, and snippets.

@kadmil
Last active November 30, 2015 05:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kadmil/ad715b26f14df17c781f to your computer and use it in GitHub Desktop.
Save kadmil/ad715b26f14df17c781f to your computer and use it in GitHub Desktop.
Mapping normalized state to tree-like view model
const initPosts = [{
id: 1,
author: 1,
comments:[1,2]
}
]
const initComments = [
{id: 1, author: 1},
{id: 2, author: 2}
]
const initAuthors = [
{id:1, name:'1'},
{id:2, name:'2'}
]
function posts(state = initPosts, action){
return state
}
function comments(state = initComments, action){
return state
}
function authors(state = initAuthors, action){
return state
}
const PostFeed = (props) => (
<div>
{props.posts.map(post => <PostComponent {...post}/>)}
</div>
)
const PostComponent = (props) => (
<div>
<div>{props.author.name}</div>
{props.comments.map(comment => (<div>comment.author.name</div>))}
</div>
)
const mapStateToProps = (state) => {
const mappedPosts = state.posts.map(post => {
const author = state.authors[post.author]
const comments = state.comments.map(comment => ({
...comment,
author: state.authors[comment.author]
}))
return {...post, author, comments}
})
}
@gaearon
Copy link

gaearon commented Oct 6, 2015

Instead of doing mapStateToProps once and trying to recreate the tree structure, instead connect() every component. Let each component receive its “primary” data as a prop (e.g. post for PostComponent, comment for CommentComponent—you don't have it yet, posts for PostFeed), but let each component grab the relevant "child props" by connect()ing each of them. For example, let PostComponent grab comments as function mapStateToProps(state, ownProps) { return { comments: ownProps.post.comments.map(id => state.comments[id]) } } and so on. This way you won't have to build any kind of expensive structure.

@kadmil
Copy link
Author

kadmil commented Oct 6, 2015

@gaearon would it be faster than single mapping? Each connect() would be fired on app state change, so we're basically 'distribute' this function between single PostComponent nodes. It's not the re-rendering bothering me, plain mapping in case of many comments becomes an issue.

@gaearon
Copy link

gaearon commented Oct 9, 2015

Can I ask you to create a project reproducing the perf issue? Then we can try to profile it. Otherwise it's just talk. :-)

@oyeanuj
Copy link

oyeanuj commented Nov 30, 2015

@kadmil: Where did you end up with this finally?

I have a similar problem but with a slightly more expensive, and nested mapping and am wondering if using reselect would help instead?

It seems that one advantage of the approach @Gaeron suggests here could be that not all the sub-components need to be re-rendered as they might need different parts of the mapping, and for a lot of them, the input might not change. For example, PostContent might not need comments and any change to those mappings will not re-render PostContent.

@gaearon: Is this a good use-case for using reselect instead of building a custom mapStateToProps method? In general, whats a good way to think about reselect vs mapStateToProps?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment