SlideShare a Scribd company logo
SELECTORS and
NORMALIZING STATE SHAPE
Improving performance in Redux
Muntasir Chowdhury
mapStateToProps()
const mapStateToProps = state => {
return {
attributeOne: state.attributeOne,
attributeTwo: state.attributeTwo,
};
}
mapStateToProps()
1. Runs when any part of the Redux store updates
2. Shallow compare of computed values (previous and new)
Shallow Compare
Render Do nothing
Not equal Equal
What is a selector?
What is a selector?
Code that derives data
mapStateToProps = state => ( { articles: state.articles });
A simple selector
mapStateToProps = state => ( {
firstThreeArticles: state.articles.splice(0, 3)
});
Transform Data
function getFirstThreeArticles(state) {
return state.articles.slice(0, 3);
}
mapStateToProps = state => ( {
firstThreeArticles: getFirstThreeArticles(state)
});
Extract to function
Adding complexity
function filterArticles(articles, filter) {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
mapStateToProps = state => ( {
articles: filterArticles(state.articles, state.filter)
});
function filterArticles(articles, filter) {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
mapStateToProps = state => ( {
articles: filterArticles(state.articles, state.filter),
usersOnline: state.usersOnline
});
Redundant derivations
function filterArticles(articles, filter) {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
mapStateToProps = state => ( {
articles: filterArticles(state.articles, state.filter),
usersOnline: state.usersOnline
});
state = {
articles: [......],
filter: "UNREAD",
usersOnline: 1629
}
function filterArticles(articles, filter) {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
mapStateToProps = state => ( {
articles: filterArticles(state.articles, state.filter),
usersOnline: state.usersOnline
});
state = {
articles: [......],
filter: "UNREAD",
usersOnline: 1629
}
state = {
articles: [......],
filter: "UNREAD",
usersOnline: 2004
}
Memoized Selectors
Reselector
createSelector( )
createSelector( [selector1, selector2...], transformFunction)
function filterArticles(articles, filter) {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
mapStateToProps = state => ( {
articles: filterArticles(state.articles, state.filter),
usersOnline: state.usersOnline
});
import { createSelector } from 'reselect'
const getFilter = (state) => state.filter;
const getArticles = (state) => state.articles;
export const filterArticles = createSelector(
[ getFilter, getArticles ],
(articles, filter) => {
switch(filter) {
“SHOW_ALL”:
return articles;
“UNREAD”:
return articles.filter(a => a.unread);
“READ”:
return articles.filter(a => !a.unread);
}
}
)
Connect Selector to Redux Store
import { connect } from 'react-redux';
import Articles from '../components/TodoList';
import { filterArticles } from '../selectors';
 
const mapStateToProps = state => {
return {
articles: filterArticles(state),
usersOnline: state.usersOnline
}
}
  
const ArticleList = connect(mapStateToProps, null)(Articles)
 
export default ArticleList
NORMALIZING STATE SHAPE
Nested State vs
Normalized State
Nested State
const articles = [
{
id : "artcle1",
user : {userId: “ui1”, username : "user1", name : "User 1"},
body : "......",
comments : [
{
id : "comment1",
user : {userId: "ui2", username : "user2", name : "User 2"},
comment : ".....",
},
{
id : "comment2",
user : {userId: "ui3", username : "user3", name : "User 3"},
comment : ".....",
}
]
},
Nested State
{
id : "article2",
user : {username : "user2", name : "User 2"},
body : "......",
comments : [
{
id : "comment3",
user : {userId: "ui3", username : "user3", name : "User 3"},
comment : ".....",
},
{
id : "comment4",
user : {userId: "ui1", username : "user1", name : "User 1"},
comment : ".....",
}
]
}
……
];
Nested State
//articleListContainer.js
mapStateToProps = (state) => ({
articles: state.articles
});
// articleList.js
const ArticleList = (articles) => ({
articles.map(article => <Article article=article />)
});
Selecting Nested State
// article.js
const Article = (article) => ({
<div>article.content</div>
{ article.comments.forEach(comments) => <Comment comment=comment /> }
});
// comment.js
const Comment = (comment) => ({
<div>comment.content</div>
<User user=comment.user />
});
Selecting Nested State
// user.js
const User = (user) => ({
<div>user.name</div>
});
Selecting Nested State
ArticleList
Article
Comment
User
User
Comment …..
Article …..
ArticleList
Article
Comment
User
User
Comment …..
Article …..
Redux Storeconnect()
//action.js
function changeUserName(userId, name) {
return {
type: CHANGE_USER_NAME,
payload: {
name
}
};
}
Updating Nested State
//reducer.js
const posts = (state, action) => {
switch(action.type) {
case "CHANGE_USER_NAME":
// find every post
// where the user as the author of the post
// or as the author of one of its comments
}
}
Updating Nested State
1. Difficult to update
a. Duplicate data
b. Complex reducer logic due to nesting
2. Higher chance of redundant re-renders
Nested State
Normalized State
Divide & Flatten
//articles_reducer.js
articles : {
byId : {
"article1" : {
id : "article1",
user : "user1",
body : "......",
comments : ["comment1", "comment2"]
},
"article2" : {
id : "article2",
user : "user2",
body : "......",
comments : ["comment3", "comment4", "comment5"]
}
},
allIds : ["article1", "article2"]
}
Normalized State
//comments_reducer.js
comments : {
byId : {
"comment1" : {
id : "comment1",
user : "user2",
comment : ".....",
},
"comment2" : {
id : "comment2",
user : "user3",
comment : ".....",
},
"comment3" : {
id : "comment3",
user : "user3",
comment : ".....",
}
},
allIds : ["comment1", "comment2", "comment3"]
}
Normalized State
//users_reducer.js
users : {
byId : {
"user1" : {
username : "user1",
name : "User 1",
}
"user2" : {
username : "user2",
name : "User 2",
}
"user3" : {
username : "user3",
name : "User 3",
}
},
allIds : ["user1", "user2", "user3"]
}
Normalized State
//articleListContainer.js
mapStateToProps = (state) => ({
articles: state.articles.allIds
});
// articleList.js
const ArticleList = (articleIds) => ({
articles.map(articleId => <Article articleId=articleId />)
});
Selecting Normalized State
// article.js
const Article = (article) => ({
<div>article.content</div>
{ article.comments.map(commentIds => <CommentContainer commentId=commentId /> }
});
Selecting Normalized State
Selecting Normalized State
//commentContainer.js
mapStateToProps = (state, ownProps) => ({
comment: state.comments.byId[ownProps.commentId]
});
// comment.js
const Comment = (comment) => ({
<div>comment.content</div>
<UserContainer user=comment.user />
});
Selecting Normalized State
//userContainer.js
mapStateToProps = (state, ownProps) => ({
user: state.user.byId[ownProps.userId]
});
// user.js
const User = (user) => ({
<div>user.name</div>
});
ArticleList
Article
Comment
User
User
Comment …..
Article …..
ArticleList
Article
Comment
User
User
Comment …..
Article …..
Redux Storeconnect()
connect()
connect()
connect()
//action.js
function changeUserName(userId, name) {
return {
type: CHANGE_USER_NAME,
payload: {
name
}
};
}
Updating Normalized
State
//userReducer.js
const usersById = (state, action) => {
switch(action.type) {
case "CHANGE_USER_NAME":
userId = action.payload.id;
changedUser = {
...state[userId],
name: action.payload.name
};
return {
...state,
[userId] : changedUser
};
default:
return state;
}
}
const usersReducer = combineReducers({
byId: usersById,
allIds: [....]
});
Updating Normalized State
Normalized State
1. Easy to update
a. Single copy of data
b. Reducer logic more manageable (less nesting)
2. More connected & independent components -> less re-renders
Other Topics
● Multiple instances of memoized selectors
● Relationships and Tables (treating Redux like a relational DB)
● Normalizing nested data from API using Normalizr
QUESTIONS

More Related Content

PDF
Chaining and function composition with lodash / underscore
PDF
Teste de Integração com DbUnit e jIntegrity
PDF
JavaScript Fundamentals with Angular and Lodash
PDF
Lodash js
PDF
12advanced Swing
PDF
Droidjam 2019 flutter isolates pdf
PPT
Executing Sql Commands
PPTX
TDD in the wild
Chaining and function composition with lodash / underscore
Teste de Integração com DbUnit e jIntegrity
JavaScript Fundamentals with Angular and Lodash
Lodash js
12advanced Swing
Droidjam 2019 flutter isolates pdf
Executing Sql Commands
TDD in the wild

What's hot (20)

PDF
Funcitonal Swift Conference: The Functional Way
PDF
Road to react hooks
PDF
Intro to JavaScript
PPTX
How to Bring Common UI Patterns to ADF
PDF
greenDAO
PPTX
Sequelize
PPTX
classes & objects in cpp overview
PDF
A evolução da persistência de dados (com sqlite) no android
PPTX
Django - sql alchemy - jquery
PDF
Advanced java practical semester 6_computer science
PPT
jQuery for beginners
PDF
Building android apps with kotlin
PDF
Deep Dive into React Hooks
PDF
Ajax chap 5
PDF
Singletons in PHP - Why they are bad and how you can eliminate them from your...
PDF
Zhongl scala summary
PDF
Design Patterns Reconsidered
PPTX
CocoaHeads Moscow. Азиз Латыпов, VIPole. «Запросы в CoreData с агрегатными фу...
PDF
#살아있다 #자프링외길12년차 #코프링2개월생존기
PPTX
Ensure code quality with vs2012
Funcitonal Swift Conference: The Functional Way
Road to react hooks
Intro to JavaScript
How to Bring Common UI Patterns to ADF
greenDAO
Sequelize
classes & objects in cpp overview
A evolução da persistência de dados (com sqlite) no android
Django - sql alchemy - jquery
Advanced java practical semester 6_computer science
jQuery for beginners
Building android apps with kotlin
Deep Dive into React Hooks
Ajax chap 5
Singletons in PHP - Why they are bad and how you can eliminate them from your...
Zhongl scala summary
Design Patterns Reconsidered
CocoaHeads Moscow. Азиз Латыпов, VIPole. «Запросы в CoreData с агрегатными фу...
#살아있다 #자프링외길12년차 #코프링2개월생존기
Ensure code quality with vs2012
Ad

Similar to Selectors and normalizing state shape (20)

PDF
Lean React - Patterns for High Performance [ploneconf2017]
PDF
Data normalization &amp; memoized denormalization
PDF
Using Array Approach, Linked List approach, and Delete Byte Approach.pdf
PDF
Intro to Redux | DreamLab Academy #3
PDF
Clean coding-practices
PDF
SE2016 Android Mikle Anokhin "Speed up application development with data bind...
PDF
Controller specs
PDF
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
PPTX
SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato
PDF
外部環境への依存をテストする
PPTX
GraphQL, Redux, and React
PDF
JavaScript and the AST
PDF
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
PDF
Materi Modern React Redux Power Point.pdf
PDF
Grammarware Memes
PDF
JJUG CCC 2011 Spring
PDF
For each task, submit your source java code file.(1) Objective Im.pdf
PDF
Redux for ReactJS Programmers
PPTX
Advance MapReduce Concepts - Module 4
PDF
spring-tutorial
Lean React - Patterns for High Performance [ploneconf2017]
Data normalization &amp; memoized denormalization
Using Array Approach, Linked List approach, and Delete Byte Approach.pdf
Intro to Redux | DreamLab Academy #3
Clean coding-practices
SE2016 Android Mikle Anokhin "Speed up application development with data bind...
Controller specs
Going Native: Leveraging the New JSON Native Datatype in Oracle 21c
SenchaCon 2016: Ext JS + React: A Match Made in UX Heaven - Mark Brocato
外部環境への依存をテストする
GraphQL, Redux, and React
JavaScript and the AST
Codepot - Pig i Hive: szybkie wprowadzenie / Pig and Hive crash course
Materi Modern React Redux Power Point.pdf
Grammarware Memes
JJUG CCC 2011 Spring
For each task, submit your source java code file.(1) Objective Im.pdf
Redux for ReactJS Programmers
Advance MapReduce Concepts - Module 4
spring-tutorial
Ad

Recently uploaded (20)

PDF
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
PDF
How to Choose the Right IT Partner for Your Business in Malaysia
PDF
How to Migrate SBCGlobal Email to Yahoo Easily
PDF
System and Network Administraation Chapter 3
PDF
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
PPTX
history of c programming in notes for students .pptx
PPTX
Introduction to Artificial Intelligence
PPTX
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
PDF
top salesforce developer skills in 2025.pdf
PDF
Understanding Forklifts - TECH EHS Solution
PPTX
Operating system designcfffgfgggggggvggggggggg
PPTX
CHAPTER 2 - PM Management and IT Context
PDF
Design an Analysis of Algorithms II-SECS-1021-03
PDF
Odoo Companies in India – Driving Business Transformation.pdf
PPTX
assetexplorer- product-overview - presentation
PPTX
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
PDF
Digital Systems & Binary Numbers (comprehensive )
PDF
Design an Analysis of Algorithms I-SECS-1021-03
PDF
Designing Intelligence for the Shop Floor.pdf
PDF
Digital Strategies for Manufacturing Companies
Why TechBuilder is the Future of Pickup and Delivery App Development (1).pdf
How to Choose the Right IT Partner for Your Business in Malaysia
How to Migrate SBCGlobal Email to Yahoo Easily
System and Network Administraation Chapter 3
EN-Survey-Report-SAP-LeanIX-EA-Insights-2025.pdf
history of c programming in notes for students .pptx
Introduction to Artificial Intelligence
Embracing Complexity in Serverless! GOTO Serverless Bengaluru
top salesforce developer skills in 2025.pdf
Understanding Forklifts - TECH EHS Solution
Operating system designcfffgfgggggggvggggggggg
CHAPTER 2 - PM Management and IT Context
Design an Analysis of Algorithms II-SECS-1021-03
Odoo Companies in India – Driving Business Transformation.pdf
assetexplorer- product-overview - presentation
Agentic AI : A Practical Guide. Undersating, Implementing and Scaling Autono...
Digital Systems & Binary Numbers (comprehensive )
Design an Analysis of Algorithms I-SECS-1021-03
Designing Intelligence for the Shop Floor.pdf
Digital Strategies for Manufacturing Companies

Selectors and normalizing state shape

  • 1. SELECTORS and NORMALIZING STATE SHAPE Improving performance in Redux Muntasir Chowdhury
  • 3. const mapStateToProps = state => { return { attributeOne: state.attributeOne, attributeTwo: state.attributeTwo, }; }
  • 4. mapStateToProps() 1. Runs when any part of the Redux store updates 2. Shallow compare of computed values (previous and new) Shallow Compare Render Do nothing Not equal Equal
  • 5. What is a selector?
  • 6. What is a selector? Code that derives data
  • 7. mapStateToProps = state => ( { articles: state.articles }); A simple selector
  • 8. mapStateToProps = state => ( { firstThreeArticles: state.articles.splice(0, 3) }); Transform Data
  • 9. function getFirstThreeArticles(state) { return state.articles.slice(0, 3); } mapStateToProps = state => ( { firstThreeArticles: getFirstThreeArticles(state) }); Extract to function
  • 11. function filterArticles(articles, filter) { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } mapStateToProps = state => ( { articles: filterArticles(state.articles, state.filter) });
  • 12. function filterArticles(articles, filter) { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } mapStateToProps = state => ( { articles: filterArticles(state.articles, state.filter), usersOnline: state.usersOnline });
  • 14. function filterArticles(articles, filter) { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } mapStateToProps = state => ( { articles: filterArticles(state.articles, state.filter), usersOnline: state.usersOnline }); state = { articles: [......], filter: "UNREAD", usersOnline: 1629 }
  • 15. function filterArticles(articles, filter) { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } mapStateToProps = state => ( { articles: filterArticles(state.articles, state.filter), usersOnline: state.usersOnline }); state = { articles: [......], filter: "UNREAD", usersOnline: 1629 } state = { articles: [......], filter: "UNREAD", usersOnline: 2004 }
  • 20. function filterArticles(articles, filter) { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } mapStateToProps = state => ( { articles: filterArticles(state.articles, state.filter), usersOnline: state.usersOnline });
  • 21. import { createSelector } from 'reselect' const getFilter = (state) => state.filter; const getArticles = (state) => state.articles; export const filterArticles = createSelector( [ getFilter, getArticles ], (articles, filter) => { switch(filter) { “SHOW_ALL”: return articles; “UNREAD”: return articles.filter(a => a.unread); “READ”: return articles.filter(a => !a.unread); } } )
  • 22. Connect Selector to Redux Store
  • 23. import { connect } from 'react-redux'; import Articles from '../components/TodoList'; import { filterArticles } from '../selectors';   const mapStateToProps = state => { return { articles: filterArticles(state), usersOnline: state.usersOnline } }    const ArticleList = connect(mapStateToProps, null)(Articles)   export default ArticleList
  • 24. NORMALIZING STATE SHAPE Nested State vs Normalized State
  • 26. const articles = [ { id : "artcle1", user : {userId: “ui1”, username : "user1", name : "User 1"}, body : "......", comments : [ { id : "comment1", user : {userId: "ui2", username : "user2", name : "User 2"}, comment : ".....", }, { id : "comment2", user : {userId: "ui3", username : "user3", name : "User 3"}, comment : ".....", } ] }, Nested State
  • 27. { id : "article2", user : {username : "user2", name : "User 2"}, body : "......", comments : [ { id : "comment3", user : {userId: "ui3", username : "user3", name : "User 3"}, comment : ".....", }, { id : "comment4", user : {userId: "ui1", username : "user1", name : "User 1"}, comment : ".....", } ] } …… ]; Nested State
  • 28. //articleListContainer.js mapStateToProps = (state) => ({ articles: state.articles }); // articleList.js const ArticleList = (articles) => ({ articles.map(article => <Article article=article />) }); Selecting Nested State
  • 29. // article.js const Article = (article) => ({ <div>article.content</div> { article.comments.forEach(comments) => <Comment comment=comment /> } }); // comment.js const Comment = (comment) => ({ <div>comment.content</div> <User user=comment.user /> }); Selecting Nested State
  • 30. // user.js const User = (user) => ({ <div>user.name</div> }); Selecting Nested State
  • 33. //action.js function changeUserName(userId, name) { return { type: CHANGE_USER_NAME, payload: { name } }; } Updating Nested State
  • 34. //reducer.js const posts = (state, action) => { switch(action.type) { case "CHANGE_USER_NAME": // find every post // where the user as the author of the post // or as the author of one of its comments } } Updating Nested State
  • 35. 1. Difficult to update a. Duplicate data b. Complex reducer logic due to nesting 2. Higher chance of redundant re-renders Nested State
  • 37. //articles_reducer.js articles : { byId : { "article1" : { id : "article1", user : "user1", body : "......", comments : ["comment1", "comment2"] }, "article2" : { id : "article2", user : "user2", body : "......", comments : ["comment3", "comment4", "comment5"] } }, allIds : ["article1", "article2"] } Normalized State
  • 38. //comments_reducer.js comments : { byId : { "comment1" : { id : "comment1", user : "user2", comment : ".....", }, "comment2" : { id : "comment2", user : "user3", comment : ".....", }, "comment3" : { id : "comment3", user : "user3", comment : ".....", } }, allIds : ["comment1", "comment2", "comment3"] } Normalized State
  • 39. //users_reducer.js users : { byId : { "user1" : { username : "user1", name : "User 1", } "user2" : { username : "user2", name : "User 2", } "user3" : { username : "user3", name : "User 3", } }, allIds : ["user1", "user2", "user3"] } Normalized State
  • 40. //articleListContainer.js mapStateToProps = (state) => ({ articles: state.articles.allIds }); // articleList.js const ArticleList = (articleIds) => ({ articles.map(articleId => <Article articleId=articleId />) }); Selecting Normalized State
  • 41. // article.js const Article = (article) => ({ <div>article.content</div> { article.comments.map(commentIds => <CommentContainer commentId=commentId /> } }); Selecting Normalized State
  • 42. Selecting Normalized State //commentContainer.js mapStateToProps = (state, ownProps) => ({ comment: state.comments.byId[ownProps.commentId] }); // comment.js const Comment = (comment) => ({ <div>comment.content</div> <UserContainer user=comment.user /> });
  • 43. Selecting Normalized State //userContainer.js mapStateToProps = (state, ownProps) => ({ user: state.user.byId[ownProps.userId] }); // user.js const User = (user) => ({ <div>user.name</div> });
  • 45. ArticleList Article Comment User User Comment ….. Article ….. Redux Storeconnect() connect() connect() connect()
  • 46. //action.js function changeUserName(userId, name) { return { type: CHANGE_USER_NAME, payload: { name } }; } Updating Normalized State
  • 47. //userReducer.js const usersById = (state, action) => { switch(action.type) { case "CHANGE_USER_NAME": userId = action.payload.id; changedUser = { ...state[userId], name: action.payload.name }; return { ...state, [userId] : changedUser }; default: return state; } } const usersReducer = combineReducers({ byId: usersById, allIds: [....] }); Updating Normalized State
  • 48. Normalized State 1. Easy to update a. Single copy of data b. Reducer logic more manageable (less nesting) 2. More connected & independent components -> less re-renders
  • 49. Other Topics ● Multiple instances of memoized selectors ● Relationships and Tables (treating Redux like a relational DB) ● Normalizing nested data from API using Normalizr