SlideShare a Scribd company logo
1 of 31
MAINTAINING SANITY IN A
LARGE REDUX APP
Nitish Kumar
@nitishk88
https://github.com/nitishkr8
8
CONTENT
Brief introduction to Redux
Structuring the workspace
Selectors and memoization
Leveraging a type system
Reducing Boilerplate by using helper utilities
REACT AND REDUX
https://articles.coltpini.com/react-redux-architecture-overview-
7b3e52004b6e
STRUCTURING THE WORKSPACE
Structuring workspace and
organizing files is one of the
hardest jobs in Computer Science.
Structuring a react/redux app can
be very daunting at times
Some established approaches to
organize a react/redux application
•Function First
•Feature First
FUNCTION FIRST
Function-first means that your top-level directories are named after the purpose
of the files inside. So you have: containers, components, actions, reducers, etc.
Pros:
•Isolates React from Redux - If you want to change the state management library,
you know which folders you need to touch. If you change the view library, you
can keep your redux folders intact.
Cons:
•Not scalable - As the app grows and you add more features, you add files into
the same folders. So you end up with having to scroll inside a single folder to
find your file.
•Tight coupling - The problem is also about coupling the folders together. A
single flow through your app will probably require files from all folders.
FEATURE FIRST
Feature-first means that the top-level directories are named after the main
features of the app: product, cart, session.
Pros:
•Scalable - This approach scales much better, because each new feature
comes with a new folder.
Cons:
•No separation b/w React and Redux - Changing one of them on the long run
is a very tricky job.
•Non-featured files – We end up with a folder common or shared, because
you want to reuse code across many features in your app.
MORE PATTERNS
•Ducks
•Fractal
DUCKS
Specifies a set of rules to bundle redux artifacts into isolated
module that is self contained.
Rules
MUST export default a function called reducer()
MUST export its action creators as functions
MUST have action types in the form npm-module-or-
app/reducer/ACTION_TYPE
MAY export its action types as UPPER_SNAKE_CASE, if an
external reducer needs to listen for them, or if it is a published
reusable library
EXAMPLE
// widgets.js
// Actions
const LOAD = 'my-app/widgets/LOAD';
const CREATE = 'my-app/widgets/CREATE';
const UPDATE = 'my-app/widgets/UPDATE';
const REMOVE = 'my-app/widgets/REMOVE';
// Reducer
export default function reducer(state = {}, action = {}) {
switch (action.type) {
// do reducer stuff
default: return state;
}
}
// Action Creators
export function loadWidgets() {
return { type: LOAD };
}
export function createWidget(widget) {
return { type: CREATE, widget };
}
export function updateWidget(widget) {
return { type: UPDATE, widget };
}
export function removeWidget(widget) {
return { type: REMOVE, widget };
}
// side effects, only as applicable
// e.g. thunks, epics, etc
export function getWidget () {
return dispatch => get('/widget').then(widget =>
dispatch(updateWidget(widget)))
}
FRACTAL
https://hackernoon.com/fractal-a-react-app-structure-for-infinite-scale-
4dab943092af
SELECTORS
What?
Are functions that take Redux state (, ownProps) as an argument and
return some data to pass to the component.
Why?
Can be used to compute derived data, allowing Redux to store the minimal
possible state
Smaller and decoupled React components. Performing data
transformations in the component makes them more coupled to the Redux
state and less generic/reusable
Performance Improvement
THE CASE FOR MEMOIZED
SELECTORS
Whenever a reducer returns, all connects get activated and calculates
their mapStateToProps to determine if the component needs an update.
The calculation most of the times is pretty unnecessary. This is rather
unavoidable but can be made really fast by leveraging immutable
operations and memoized selectors.
Memoized selectors are efficient. A selector is not recomputed unless one
of its arguments changes.
Selectors can be composable. They can be used as input to other
selectors.
RE-SELECT
import { createSelector } from 'reselect'
const shopItemsSelector = state =>
state.shop.items
const taxPercentSelector = state =>
state.shop.taxPercent
const subtotalSelector = createSelector(
shopItemsSelector,
items => items.reduce((acc, item) => acc +
item.value, 0)
)
const taxSelector = createSelector(
subtotalSelector,
taxPercentSelector,
(subtotal, taxPercent) => subtotal * (taxPercent /
100)
)
export const totalSelector = createSelector(
subtotalSelector,
taxSelector,
(subtotal, tax) => ({ total: subtotal + tax })
)
let exampleState = {
shop: {
taxPercent: 8,
items: [
{ name: 'apple', value: 1.20 },
{ name: 'orange', value: 0.95 },
]
}
}
console.log(subtotalSelector(exampleState)) // 2.15
console.log(taxSelector(exampleState)) // 0.172
console.log(totalSelector(exampleState)) // { total:
2.322 }
LEVERAGING FLOW
Flow is a static type checker for JavaScript. It works by analyzing your
source code, reading (and inferring) type information and making sure
there are no conflicts. It can also power a lot of IDE-like features, for
example auto-complete, jump-to-definition, etc.
Redux has three parts that could be typed:
Actions
State
Reducers
TYPING STATE
type State = {
users: Array<{
id: string,
name: string
}>,
activeUserID: string,
// ...
}
We can enforce immutability in Flow by
making every property effectively “read-
only” using “covariant” properties throughout
your state object. Flow will complain when
you try to write to any of these properties.
type State = {
+foo: string
};
let state: State = {
foo: "foo"
};
state.foo = "bar"; // Error!
TYPING ACTIONS
The base type for Redux actions is an object with a type property.
type Action = {
+type: string
}
We can define Action type to be as simple as
type Action = {
+type: string
payload: Object
}
We can do much better than using constants for action types. Let’s start by
defining all possible actions flowing through our app. We will use a union
type for this.
type Action = { type: 'LOGGED_IN', userName: string }
| { type: 'LOGGED_OUT' }
{ type: 'LOGGED_IN', userName: 'foo' } // valid
{ type: 'LOGGED_IN', login: 'foo' } // `login` is not `userName`
{ type: 'LOGGED_IN' } // no `userName`
{ type: 'TYPO_HERE' } // `type` doesn't exist
Having all possible actions typed like this is great, because it’s very clear
what can happen inside our app.
The awesome thing about Flow’s support for the tagged unions is that it can
narrow down the action type depending on your code control flow:
function user(state: State, action: Action): State {
if (action.type === 'LOGGED_IN') {
// In this `if` branch Flow narrowed down the type
// and it knows that action has `userName: string` field
return { isLoggedIn: true, name: action.userName };
}
}
TYPING ACTION CREATORS
To type the action creator, just add a return type `Action` disjoint union declared earlier
function logOut(): Action {
return { type: 'LOGGED_OUT' }
}
In case we are using custom middleware to dispatch a Promise of Action
type PromiseAction = Promise<Action>
async function logIn(login: string, pass: string): PromiseAction {
let response = await fetch(...);
// Do something...
return {
type: 'LOGGED_IN',
userName: login,
}}
TYPING THUNK ACTIONS
type Action =
| { type: "FOO", foo: number }
| { type: "BAR", bar: boolean };
type GetState = () => State;
type PromiseAction = Promise<Action>;
type ThunkAction = (dispatch: Dispatch, getState: GetState) =>
any;
type Dispatch = (action: Action | ThunkAction | PromiseAction
| Array<Action>) => any;
function foo(): ThunkAction {
return (dispatch, getState) => {
const baz = getState().baz
dispatch({ type: "BAR", bar: true })
doSomethingAsync(baz)
.then(value => {
dispatch({ type: "FOO", foo: value })
})
}
}
TYPING REDUCERS
Reducers take the state and actions that we’ve
typed and pulls them together for one method.
function reducer(state: State, action: Action): State {
// ...
}
We can also validate that every single type of action has been
handled by using the empty type in your default case.
type State = { +value: boolean };
type FooAction = { type: "FOO", foo: boolean };
type BarAction = { type: "BAR", bar: boolean };
type Action = FooAction | BarAction;
function reducer(state: State, action: Action): State {
switch (action.type) {
case "FOO": return { ...state, value: action.foo };
case "BAR": return { ...state, value: action.bar };
default:
(action: empty);
return state;
}
}
REDUCING BOILERPLATE
The most common complaint about Redux is how it makes you write a lot of
boilerplate. We’ll see how Redux lets us choose how verbose we'd like our
code to be, depending on personal style, team preferences, longer term
maintainability, etc.
We can write our utilities for generate the following
Action creators
Reducers
MAKING ACTION CREATORS
A function that generates an action creator
function createAction(type, ...argNames) {
return function (...args) {
let action = { type }
argNames.forEach((arg, index) => {
action[argNames[index]] = args[index]
})
return action
}}
function addTodo(text) {
return {
type: 'ADD_TODO',
text
}
}
function editTodo(id, text) {
return {
type: 'EDIT_TODO',
id,
text
}
}
function
removeTodo(id) {
return {
type:
'REMOVE_TODO',
id
}
}
const addTodo = createAction ('ADD_TODO', 'text')
const editTodo = createAction ('EDIT_TODO', 'id', 'text')
const removeTodo = createAction ('REMOVE_TODO', 'id')
MAKING ASYNC ACTION CREATORS
function createThunkAction(actionType,
actionThunkCreator) {
function fn(...actionArgs) {
var thunk = actionThunkCreator(...actionArgs)
return async function(dispatch, getState) {
try {
let payload = await thunk(dispatch, getState)
dispatch({ type: actionType, payload })
} catch (error) {
dispatch({ type: actionType, payload: error, error:
true
})
throw error
}
}}
fn.toString = () => actionType
return fn}
const fetchUsersForTitle =
createThunkAction(‘FETCH_USERS’, jobTitle => {
let result
return async (dispatch, getState) => {
// fetch users
result = await UserApi.list(// ...})
return result
}
})
GENERATING REDUCERS
We can write a function that lets us express
reducers as an object mapping from action types
to handlers.
function createReducer(initialState, handlers) {
return function reducer(state = initialState, action) {
if (handlers.hasOwnProperty(action.type)) {
return handlers[action.type](state, action)
} else {
return state
}
}
}
Then define our reducers like this
const todos = createReducer([], {
['ADD_TODO'](state, action) {
let text = action.text.trim()
return [...state, text]
},
[TOGGLE_TODO'](state, action) {
// toggle and return new state
}
})
UTILITY LIBRARIES
redux-act
An opinionated lib to create actions and reducers for Redux. The main goal is to use
actions themselves as references inside the reducers rather than string constants.
redux-actions
Utility belt for FSA-compliant actions in Redux. It provides helpers for both handling and
creating action(s)
flux-standard-action (FSA) – A human-friendly standard for Flux action objects
REDUX-ACTIONS
API
createAction(s)
handleAction(s)
createAction(type)
const increment = createAction('INCREMENT')
const decrement = createAction('DECREMENT')
increment() // { type: 'INCREMENT' }
decrement() // { type: 'DECREMENT' }
increment(10) // { type: 'INCREMENT', payload: 10
}
decrement([1, 42]) // { type: 'DECREMENT', payload: [1,
42] }
createAction(type,
payloadCreator)
const actionOne = createAction('ACTION_ONE', (key,
value) => ({ [key]: value }))
expect(actionOne('key', 1)).to.deep.equal({
type: 'ACTION_ONE',
payload: { key: 1 }
})
createActions(actionMap)
const { addTodo, removeTodo } = createActions({
ADD_TODO: todo => ({ todo }),
REMOVE_TODO: todo => ({ todo }),
})
CREATE ACTION
handleAction(type, reducer,
defaultState)
handleAction('APP/COUNTER/INCREMENT', (state, action)
=> ({
counter: state.counter + action.payload.amount,
}), defaultState)
handleAction(type, reducerMap,
defaultState)
handleAction('FETCH_DATA', {
next(state, action) {...},
throw(state, action) {...},
}, defaultState)
handleActions(reducerMap,
defaultState)
const reducer = handleActions({
INCREMENT: (state, action) => ({
counter: state.counter + action.payload
}),
DECREMENT: (state, action) => ({
counter: state.counter - action.payload
})
}, { counter: 0 })
HANDLE ACTION
THANK
YOU
REFERENCES
https://github.com/erikras/ducks-modular-redux
https://hackernoon.com/fractal-a-react-app-structure-for-infinite-
scale-4dab943092af
https://flow.org/en/docs/react/redux/
https://github.com/pauldijou/redux-act
https://github.com/reduxactions/redux-actions
https://github.com/acdlite/flux-standard-action
https://github.com/reactjs/reselect

More Related Content

What's hot

Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.AngularEvan Schultz
 
Rise of state_machines
Rise of state_machinesRise of state_machines
Rise of state_machinesMounir Boudraa
 
Angular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of StatesAngular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of StatesOren Farhi
 
Web Developer make the most out of your Database !
Web Developer make the most out of your Database !Web Developer make the most out of your Database !
Web Developer make the most out of your Database !Jean-Marc Desvaux
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfoliovitabile
 
Refactoring in Practice - Sunnyconf 2010
Refactoring in Practice - Sunnyconf 2010Refactoring in Practice - Sunnyconf 2010
Refactoring in Practice - Sunnyconf 2010Alex Sharp
 
Evan Schultz - Angular Camp - ng2-redux
Evan Schultz - Angular Camp - ng2-reduxEvan Schultz - Angular Camp - ng2-redux
Evan Schultz - Angular Camp - ng2-reduxEvan Schultz
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails Mohit Jain
 
Introduction To Angular's reactive forms
Introduction To Angular's reactive formsIntroduction To Angular's reactive forms
Introduction To Angular's reactive formsNir Kaufman
 
Frank Rodenbaugh Portfolio
Frank Rodenbaugh PortfolioFrank Rodenbaugh Portfolio
Frank Rodenbaugh PortfolioFrankRodenbaugh
 
Extending Redux in the Server Side
Extending Redux in the Server SideExtending Redux in the Server Side
Extending Redux in the Server SideIgnacio Martín
 
Oracle - Program with PL/SQL - Lession 17
Oracle - Program with PL/SQL - Lession 17Oracle - Program with PL/SQL - Lession 17
Oracle - Program with PL/SQL - Lession 17Thuan Nguyen
 
Styling recipes for Angular components
Styling recipes for Angular componentsStyling recipes for Angular components
Styling recipes for Angular componentsNir Kaufman
 

What's hot (20)

Oracle: Basic SQL
Oracle: Basic SQLOracle: Basic SQL
Oracle: Basic SQL
 
React/Redux
React/ReduxReact/Redux
React/Redux
 
Reactive.architecture.with.Angular
Reactive.architecture.with.AngularReactive.architecture.with.Angular
Reactive.architecture.with.Angular
 
Rise of state_machines
Rise of state_machinesRise of state_machines
Rise of state_machines
 
Angular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of StatesAngular2 & ngrx/store: Game of States
Angular2 & ngrx/store: Game of States
 
Web Developer make the most out of your Database !
Web Developer make the most out of your Database !Web Developer make the most out of your Database !
Web Developer make the most out of your Database !
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfolio
 
Stored procedures
Stored proceduresStored procedures
Stored procedures
 
Ngrx
NgrxNgrx
Ngrx
 
Refactoring in Practice - Sunnyconf 2010
Refactoring in Practice - Sunnyconf 2010Refactoring in Practice - Sunnyconf 2010
Refactoring in Practice - Sunnyconf 2010
 
Evan Schultz - Angular Camp - ng2-redux
Evan Schultz - Angular Camp - ng2-reduxEvan Schultz - Angular Camp - ng2-redux
Evan Schultz - Angular Camp - ng2-redux
 
Ruby on rails
Ruby on rails Ruby on rails
Ruby on rails
 
Introduction To Angular's reactive forms
Introduction To Angular's reactive formsIntroduction To Angular's reactive forms
Introduction To Angular's reactive forms
 
Framework Project Portfolio
Framework Project PortfolioFramework Project Portfolio
Framework Project Portfolio
 
Stored procedure
Stored procedureStored procedure
Stored procedure
 
Frank Rodenbaugh Portfolio
Frank Rodenbaugh PortfolioFrank Rodenbaugh Portfolio
Frank Rodenbaugh Portfolio
 
Extending Redux in the Server Side
Extending Redux in the Server SideExtending Redux in the Server Side
Extending Redux in the Server Side
 
Workshop 17: EmberJS parte II
Workshop 17: EmberJS parte IIWorkshop 17: EmberJS parte II
Workshop 17: EmberJS parte II
 
Oracle - Program with PL/SQL - Lession 17
Oracle - Program with PL/SQL - Lession 17Oracle - Program with PL/SQL - Lession 17
Oracle - Program with PL/SQL - Lession 17
 
Styling recipes for Angular components
Styling recipes for Angular componentsStyling recipes for Angular components
Styling recipes for Angular components
 

Similar to Maintaining sanity in a large redux app

Redux training
Redux trainingRedux training
Redux trainingdasersoft
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux jsCitrix
 
How to use redux with react hooks in react native application
How to use redux with react hooks in react native applicationHow to use redux with react hooks in react native application
How to use redux with react hooks in react native applicationKaty Slemon
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creatorsGeorge Bukhanov
 
Introduction to Redux (for Angular and React devs)
Introduction to Redux (for Angular and React devs)Introduction to Redux (for Angular and React devs)
Introduction to Redux (for Angular and React devs)Fabio Biondi
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with ReduxVedran Blaženka
 
Pieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React NativePieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React Nativetlv-ios-dev
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to productionFDConf
 
Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020Jerry Liao
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxVisual Engineering
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 DreamLab
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to productionJenya Terpil
 
Reactивная тяга
Reactивная тягаReactивная тяга
Reactивная тягаVitebsk Miniq
 
Leture5 exercise onactivities
Leture5 exercise onactivitiesLeture5 exercise onactivities
Leture5 exercise onactivitiesmaamir farooq
 
Lecture exercise on activities
Lecture exercise on activitiesLecture exercise on activities
Lecture exercise on activitiesmaamir farooq
 
Lec 28 - operator overloading
Lec 28 - operator overloadingLec 28 - operator overloading
Lec 28 - operator overloadingPrincess Sam
 

Similar to Maintaining sanity in a large redux app (20)

Redux training
Redux trainingRedux training
Redux training
 
Getting started with Redux js
Getting started with Redux jsGetting started with Redux js
Getting started with Redux js
 
How to use redux with react hooks in react native application
How to use redux with react hooks in react native applicationHow to use redux with react hooks in react native application
How to use redux with react hooks in react native application
 
The evolution of redux action creators
The evolution of redux action creatorsThe evolution of redux action creators
The evolution of redux action creators
 
Simple React Todo List
Simple React Todo ListSimple React Todo List
Simple React Todo List
 
Introduction to Redux (for Angular and React devs)
Introduction to Redux (for Angular and React devs)Introduction to Redux (for Angular and React devs)
Introduction to Redux (for Angular and React devs)
 
React state managmenet with Redux
React state managmenet with ReduxReact state managmenet with Redux
React state managmenet with Redux
 
Pieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React NativePieter De Baets - An introduction to React Native
Pieter De Baets - An introduction to React Native
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
 
Stay with React.js in 2020
Stay with React.js in 2020Stay with React.js in 2020
Stay with React.js in 2020
 
React redux
React reduxReact redux
React redux
 
Workshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & ReduxWorkshop 20: ReactJS Part II Flux Pattern & Redux
Workshop 20: ReactJS Part II Flux Pattern & Redux
 
Understanding redux
Understanding reduxUnderstanding redux
Understanding redux
 
Reducers+flux=redux
Reducers+flux=reduxReducers+flux=redux
Reducers+flux=redux
 
Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3 Intro to Redux | DreamLab Academy #3
Intro to Redux | DreamLab Academy #3
 
Redux. From twitter hype to production
Redux. From twitter hype to productionRedux. From twitter hype to production
Redux. From twitter hype to production
 
Reactивная тяга
Reactивная тягаReactивная тяга
Reactивная тяга
 
Leture5 exercise onactivities
Leture5 exercise onactivitiesLeture5 exercise onactivities
Leture5 exercise onactivities
 
Lecture exercise on activities
Lecture exercise on activitiesLecture exercise on activities
Lecture exercise on activities
 
Lec 28 - operator overloading
Lec 28 - operator overloadingLec 28 - operator overloading
Lec 28 - operator overloading
 

Recently uploaded

(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service
(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service
(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Serviceranjana rawat
 
Analog to Digital and Digital to Analog Converter
Analog to Digital and Digital to Analog ConverterAnalog to Digital and Digital to Analog Converter
Analog to Digital and Digital to Analog ConverterAbhinavSharma374939
 
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escortsranjana rawat
 
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSMANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSSIVASHANKAR N
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVRajaP95
 
SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )Tsuyoshi Horigome
 
Microscopic Analysis of Ceramic Materials.pptx
Microscopic Analysis of Ceramic Materials.pptxMicroscopic Analysis of Ceramic Materials.pptx
Microscopic Analysis of Ceramic Materials.pptxpurnimasatapathy1234
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Dr.Costas Sachpazis
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxupamatechverse
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130Suhani Kapoor
 
Coefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxCoefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxAsutosh Ranjan
 
Introduction to Multiple Access Protocol.pptx
Introduction to Multiple Access Protocol.pptxIntroduction to Multiple Access Protocol.pptx
Introduction to Multiple Access Protocol.pptxupamatechverse
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxpranjaldaimarysona
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidNikhilNagaraju
 
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSAPPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSKurinjimalarL3
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...ranjana rawat
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsCall Girls in Nagpur High Profile
 

Recently uploaded (20)

(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service
(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service
(RIA) Call Girls Bhosari ( 7001035870 ) HI-Fi Pune Escorts Service
 
Analog to Digital and Digital to Analog Converter
Analog to Digital and Digital to Analog ConverterAnalog to Digital and Digital to Analog Converter
Analog to Digital and Digital to Analog Converter
 
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts
(MEERA) Dapodi Call Girls Just Call 7001035870 [ Cash on Delivery ] Pune Escorts
 
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLSMANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
MANUFACTURING PROCESS-II UNIT-5 NC MACHINE TOOLS
 
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IVHARMONY IN THE NATURE AND EXISTENCE - Unit-IV
HARMONY IN THE NATURE AND EXISTENCE - Unit-IV
 
SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )SPICE PARK APR2024 ( 6,793 SPICE Models )
SPICE PARK APR2024 ( 6,793 SPICE Models )
 
Microscopic Analysis of Ceramic Materials.pptx
Microscopic Analysis of Ceramic Materials.pptxMicroscopic Analysis of Ceramic Materials.pptx
Microscopic Analysis of Ceramic Materials.pptx
 
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCRCall Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
Call Us -/9953056974- Call Girls In Vikaspuri-/- Delhi NCR
 
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
9953056974 Call Girls In South Ex, Escorts (Delhi) NCR.pdf
 
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
Structural Analysis and Design of Foundations: A Comprehensive Handbook for S...
 
Introduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptxIntroduction and different types of Ethernet.pptx
Introduction and different types of Ethernet.pptx
 
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(PRIYA) Rajgurunagar Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
VIP Call Girls Service Hitech City Hyderabad Call +91-8250192130
 
Coefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptxCoefficient of Thermal Expansion and their Importance.pptx
Coefficient of Thermal Expansion and their Importance.pptx
 
Introduction to Multiple Access Protocol.pptx
Introduction to Multiple Access Protocol.pptxIntroduction to Multiple Access Protocol.pptx
Introduction to Multiple Access Protocol.pptx
 
Processing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptxProcessing & Properties of Floor and Wall Tiles.pptx
Processing & Properties of Floor and Wall Tiles.pptx
 
main PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfidmain PPT.pptx of girls hostel security using rfid
main PPT.pptx of girls hostel security using rfid
 
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICSAPPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
APPLICATIONS-AC/DC DRIVES-OPERATING CHARACTERISTICS
 
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
(ANVI) Koregaon Park Call Girls Just Call 7001035870 [ Cash on Delivery ] Pun...
 
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur EscortsHigh Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
High Profile Call Girls Nagpur Meera Call 7001035870 Meet With Nagpur Escorts
 

Maintaining sanity in a large redux app

  • 1. MAINTAINING SANITY IN A LARGE REDUX APP Nitish Kumar @nitishk88 https://github.com/nitishkr8 8
  • 2. CONTENT Brief introduction to Redux Structuring the workspace Selectors and memoization Leveraging a type system Reducing Boilerplate by using helper utilities
  • 4. STRUCTURING THE WORKSPACE Structuring workspace and organizing files is one of the hardest jobs in Computer Science. Structuring a react/redux app can be very daunting at times Some established approaches to organize a react/redux application •Function First •Feature First
  • 5. FUNCTION FIRST Function-first means that your top-level directories are named after the purpose of the files inside. So you have: containers, components, actions, reducers, etc. Pros: •Isolates React from Redux - If you want to change the state management library, you know which folders you need to touch. If you change the view library, you can keep your redux folders intact. Cons: •Not scalable - As the app grows and you add more features, you add files into the same folders. So you end up with having to scroll inside a single folder to find your file. •Tight coupling - The problem is also about coupling the folders together. A single flow through your app will probably require files from all folders.
  • 6. FEATURE FIRST Feature-first means that the top-level directories are named after the main features of the app: product, cart, session. Pros: •Scalable - This approach scales much better, because each new feature comes with a new folder. Cons: •No separation b/w React and Redux - Changing one of them on the long run is a very tricky job. •Non-featured files – We end up with a folder common or shared, because you want to reuse code across many features in your app.
  • 8. DUCKS Specifies a set of rules to bundle redux artifacts into isolated module that is self contained. Rules MUST export default a function called reducer() MUST export its action creators as functions MUST have action types in the form npm-module-or- app/reducer/ACTION_TYPE MAY export its action types as UPPER_SNAKE_CASE, if an external reducer needs to listen for them, or if it is a published reusable library
  • 9. EXAMPLE // widgets.js // Actions const LOAD = 'my-app/widgets/LOAD'; const CREATE = 'my-app/widgets/CREATE'; const UPDATE = 'my-app/widgets/UPDATE'; const REMOVE = 'my-app/widgets/REMOVE'; // Reducer export default function reducer(state = {}, action = {}) { switch (action.type) { // do reducer stuff default: return state; } } // Action Creators export function loadWidgets() { return { type: LOAD }; } export function createWidget(widget) { return { type: CREATE, widget }; } export function updateWidget(widget) { return { type: UPDATE, widget }; } export function removeWidget(widget) { return { type: REMOVE, widget }; } // side effects, only as applicable // e.g. thunks, epics, etc export function getWidget () { return dispatch => get('/widget').then(widget => dispatch(updateWidget(widget))) }
  • 11. SELECTORS What? Are functions that take Redux state (, ownProps) as an argument and return some data to pass to the component. Why? Can be used to compute derived data, allowing Redux to store the minimal possible state Smaller and decoupled React components. Performing data transformations in the component makes them more coupled to the Redux state and less generic/reusable Performance Improvement
  • 12. THE CASE FOR MEMOIZED SELECTORS Whenever a reducer returns, all connects get activated and calculates their mapStateToProps to determine if the component needs an update. The calculation most of the times is pretty unnecessary. This is rather unavoidable but can be made really fast by leveraging immutable operations and memoized selectors. Memoized selectors are efficient. A selector is not recomputed unless one of its arguments changes. Selectors can be composable. They can be used as input to other selectors.
  • 13. RE-SELECT import { createSelector } from 'reselect' const shopItemsSelector = state => state.shop.items const taxPercentSelector = state => state.shop.taxPercent const subtotalSelector = createSelector( shopItemsSelector, items => items.reduce((acc, item) => acc + item.value, 0) ) const taxSelector = createSelector( subtotalSelector, taxPercentSelector, (subtotal, taxPercent) => subtotal * (taxPercent / 100) ) export const totalSelector = createSelector( subtotalSelector, taxSelector, (subtotal, tax) => ({ total: subtotal + tax }) ) let exampleState = { shop: { taxPercent: 8, items: [ { name: 'apple', value: 1.20 }, { name: 'orange', value: 0.95 }, ] } } console.log(subtotalSelector(exampleState)) // 2.15 console.log(taxSelector(exampleState)) // 0.172 console.log(totalSelector(exampleState)) // { total: 2.322 }
  • 14. LEVERAGING FLOW Flow is a static type checker for JavaScript. It works by analyzing your source code, reading (and inferring) type information and making sure there are no conflicts. It can also power a lot of IDE-like features, for example auto-complete, jump-to-definition, etc. Redux has three parts that could be typed: Actions State Reducers
  • 15. TYPING STATE type State = { users: Array<{ id: string, name: string }>, activeUserID: string, // ... } We can enforce immutability in Flow by making every property effectively “read- only” using “covariant” properties throughout your state object. Flow will complain when you try to write to any of these properties. type State = { +foo: string }; let state: State = { foo: "foo" }; state.foo = "bar"; // Error!
  • 16. TYPING ACTIONS The base type for Redux actions is an object with a type property. type Action = { +type: string } We can define Action type to be as simple as type Action = { +type: string payload: Object } We can do much better than using constants for action types. Let’s start by defining all possible actions flowing through our app. We will use a union type for this. type Action = { type: 'LOGGED_IN', userName: string } | { type: 'LOGGED_OUT' } { type: 'LOGGED_IN', userName: 'foo' } // valid { type: 'LOGGED_IN', login: 'foo' } // `login` is not `userName` { type: 'LOGGED_IN' } // no `userName` { type: 'TYPO_HERE' } // `type` doesn't exist
  • 17. Having all possible actions typed like this is great, because it’s very clear what can happen inside our app. The awesome thing about Flow’s support for the tagged unions is that it can narrow down the action type depending on your code control flow: function user(state: State, action: Action): State { if (action.type === 'LOGGED_IN') { // In this `if` branch Flow narrowed down the type // and it knows that action has `userName: string` field return { isLoggedIn: true, name: action.userName }; } }
  • 18. TYPING ACTION CREATORS To type the action creator, just add a return type `Action` disjoint union declared earlier function logOut(): Action { return { type: 'LOGGED_OUT' } } In case we are using custom middleware to dispatch a Promise of Action type PromiseAction = Promise<Action> async function logIn(login: string, pass: string): PromiseAction { let response = await fetch(...); // Do something... return { type: 'LOGGED_IN', userName: login, }}
  • 19. TYPING THUNK ACTIONS type Action = | { type: "FOO", foo: number } | { type: "BAR", bar: boolean }; type GetState = () => State; type PromiseAction = Promise<Action>; type ThunkAction = (dispatch: Dispatch, getState: GetState) => any; type Dispatch = (action: Action | ThunkAction | PromiseAction | Array<Action>) => any; function foo(): ThunkAction { return (dispatch, getState) => { const baz = getState().baz dispatch({ type: "BAR", bar: true }) doSomethingAsync(baz) .then(value => { dispatch({ type: "FOO", foo: value }) }) } }
  • 20. TYPING REDUCERS Reducers take the state and actions that we’ve typed and pulls them together for one method. function reducer(state: State, action: Action): State { // ... } We can also validate that every single type of action has been handled by using the empty type in your default case. type State = { +value: boolean }; type FooAction = { type: "FOO", foo: boolean }; type BarAction = { type: "BAR", bar: boolean }; type Action = FooAction | BarAction; function reducer(state: State, action: Action): State { switch (action.type) { case "FOO": return { ...state, value: action.foo }; case "BAR": return { ...state, value: action.bar }; default: (action: empty); return state; } }
  • 21. REDUCING BOILERPLATE The most common complaint about Redux is how it makes you write a lot of boilerplate. We’ll see how Redux lets us choose how verbose we'd like our code to be, depending on personal style, team preferences, longer term maintainability, etc. We can write our utilities for generate the following Action creators Reducers
  • 22. MAKING ACTION CREATORS A function that generates an action creator function createAction(type, ...argNames) { return function (...args) { let action = { type } argNames.forEach((arg, index) => { action[argNames[index]] = args[index] }) return action }}
  • 23. function addTodo(text) { return { type: 'ADD_TODO', text } } function editTodo(id, text) { return { type: 'EDIT_TODO', id, text } } function removeTodo(id) { return { type: 'REMOVE_TODO', id } } const addTodo = createAction ('ADD_TODO', 'text') const editTodo = createAction ('EDIT_TODO', 'id', 'text') const removeTodo = createAction ('REMOVE_TODO', 'id')
  • 24. MAKING ASYNC ACTION CREATORS function createThunkAction(actionType, actionThunkCreator) { function fn(...actionArgs) { var thunk = actionThunkCreator(...actionArgs) return async function(dispatch, getState) { try { let payload = await thunk(dispatch, getState) dispatch({ type: actionType, payload }) } catch (error) { dispatch({ type: actionType, payload: error, error: true }) throw error } }} fn.toString = () => actionType return fn} const fetchUsersForTitle = createThunkAction(‘FETCH_USERS’, jobTitle => { let result return async (dispatch, getState) => { // fetch users result = await UserApi.list(// ...}) return result } })
  • 25. GENERATING REDUCERS We can write a function that lets us express reducers as an object mapping from action types to handlers. function createReducer(initialState, handlers) { return function reducer(state = initialState, action) { if (handlers.hasOwnProperty(action.type)) { return handlers[action.type](state, action) } else { return state } } } Then define our reducers like this const todos = createReducer([], { ['ADD_TODO'](state, action) { let text = action.text.trim() return [...state, text] }, [TOGGLE_TODO'](state, action) { // toggle and return new state } })
  • 26. UTILITY LIBRARIES redux-act An opinionated lib to create actions and reducers for Redux. The main goal is to use actions themselves as references inside the reducers rather than string constants. redux-actions Utility belt for FSA-compliant actions in Redux. It provides helpers for both handling and creating action(s) flux-standard-action (FSA) – A human-friendly standard for Flux action objects
  • 28. createAction(type) const increment = createAction('INCREMENT') const decrement = createAction('DECREMENT') increment() // { type: 'INCREMENT' } decrement() // { type: 'DECREMENT' } increment(10) // { type: 'INCREMENT', payload: 10 } decrement([1, 42]) // { type: 'DECREMENT', payload: [1, 42] } createAction(type, payloadCreator) const actionOne = createAction('ACTION_ONE', (key, value) => ({ [key]: value })) expect(actionOne('key', 1)).to.deep.equal({ type: 'ACTION_ONE', payload: { key: 1 } }) createActions(actionMap) const { addTodo, removeTodo } = createActions({ ADD_TODO: todo => ({ todo }), REMOVE_TODO: todo => ({ todo }), }) CREATE ACTION
  • 29. handleAction(type, reducer, defaultState) handleAction('APP/COUNTER/INCREMENT', (state, action) => ({ counter: state.counter + action.payload.amount, }), defaultState) handleAction(type, reducerMap, defaultState) handleAction('FETCH_DATA', { next(state, action) {...}, throw(state, action) {...}, }, defaultState) handleActions(reducerMap, defaultState) const reducer = handleActions({ INCREMENT: (state, action) => ({ counter: state.counter + action.payload }), DECREMENT: (state, action) => ({ counter: state.counter - action.payload }) }, { counter: 0 }) HANDLE ACTION