Redux or Not Redux
Gergel Gorvat
Volodymyr Vyshko

JS Community

Gergel Gorvat

Volodymyr Vyshko



JS Community
Agenda
Intro
Why you should use Redux
Why you shouldn't
Overview
State management
JavaScript community
In general

User
Scene
Router
State
What is the state?

State
Allocated objects
All the variables
File descriptors
Network sockets
It is basically all of the information that represents what is currently happening in the application.
What is the state management?
What is your opinion?

How data gets into/out of a store

How business logic interacts with the UI
Application architecture

How information flows through a system
Data persistence
Programming paradigms
networking and caching
Presentation behavior

When would I need to use a state management tool?
You have reasonable amounts of data changing over time
Many people working on the project, you want a consistent way to work with state
You don't want to reinvent the wheel again by your own
You want to use some extensions for easier debugging


56.4k
Why should I use Redux?

TL;DR
Is Redux dead, dying, deprecated, or about to be replaced?
No.
Hi, I'm a Redux maintainer.
No, Context does not replace Redux, although there is some overlap. And yes, Redux will continue to be very relevant and useful for a long time. It's currently used by 50% of React apps, and lots of folks are continuing to learn it on a daily basis.

Mark Erikson
Redux good points
Consistent architectural pattern
Debugging capabilities
Middleware
Addons and extensibility
Cross-platform and cross-framework usage
Better performance than Conext
Redux = proven by time, gives you a pattern
Still good in many cases
Not a silver bullet, but

Boilerplate problem
Boilerplate problem
Boilerplate problem
Boilerplate problem
Boilerplate problem
Boilerplate problem
Boilerplate problem



const types = {
INCREMENT: 'counter/redux/increment',
DECREMENT: 'counter/redux/decrement',
RESET: 'counter/redux/reset',
SET_STEP: 'counter/redux/setStep',
};
export default types;
import types from './types';
export const setStep = (payload) => ({
type: types.SET_STEP,
payload,
});
export const increment = (payload) => ({
type: types.INCREMENT,
payload,
});
export const decrement = (payload) => ({
type: types.DECREMENT,
payload,
});
export const reset = () => ({
type: types.RESET,
});
import { combineReducers } from 'redux';
import types from './types';
const initialState = {
step: 10,
value: 0,
};
const step = (state = initialState.step, action) => {
switch (action.type) {
case types.SET_STEP:
return action.payload;
default:
return state;
}
};
const value = (state = initialState.value, action) => {
switch (action.type) {
case types.INCREMENT:
return state + action.payload;
case types.DECREMENT:
return state - action.payload;
case types.RESET:
return initialState.value;
default:
return state;
}
};
export default combineReducers({ step, value });

How to get rid of the boilerplate?
¯\_(ツ)_/¯

The solution
Redux Toolkit





From the Redux Team
https://redux-toolkit.js.org

import { createSlice } from '@reduxjs/toolkit';
const initialState = {
step: 10,
value: 0,
};
export const counterSlice = createSlice({
name: 'counter/toolkit',
initialState,
reducers: {
increment: (state, action) => {
state.value += action.payload;
},
decrement: (state, action) => {
state.value -= action.payload;
},
setStep: (state, action) => {
state.step = action.payload;
},
},
});
export const {
increment,
decrement,
setStep
} = counterSlice.actions;
export default counterSlice.reducer;


thunk / createAsyncThunk
import { createAsyncThunk, createSlice } from '@reduxjs/toolkit'
import { userAPI } from './userAPI'
// First, create the thunk action
const fetchUserById = createAsyncThunk(
'users/fetchByIdStatus',
async (userId, thunkAPI) => {
const response = await userAPI.fetchById(userId)
return response.data
}
)
// Then, handle actions in your reducers:
const usersSlice = createSlice({
name: 'users',
initialState: { entities: [], loading: 'idle' },
reducers: {
// standard reducer logic, with auto-generated action types per reducer
},
extraReducers: (builder) => {
// Add reducers for additional action types here, and handle loading state as needed
builder.addCase(fetchUserById.fulfilled, (state, action) => {
// Add user to the state array
state.entities.push(action.payload)
})
},
})
// Later, dispatch the thunk as needed in the app
dispatch(fetchUserById(123)
- pending: 'users/requestStatus/pending'
- fulfilled: 'users/requestStatus/fulfilled'
- rejected: 'users/requestStatus/rejected'
What else?
store.js
import { createStore, applyMiddleware, compose } from 'redux';
import thunk from 'redux-thunk';
import reducer from './rootReducer';
const composeEnhancers =
(process.env.NODE_ENV === 'development' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__) ||
compose;
const middleware = [thunk];
export const store = createStore(
reducer,
/* preloadedState, */
composeEnhancers(applyMiddleware(...middleware)),
);
import { configureStore } from '@reduxjs/toolkit';
import reducer from './rootReducer';
export const store = configureStore({
reducer,
devTools: process.env.NODE_ENV === 'development', // true by default
});

Or Not Redux?


My experience with Redux
function mapStateToProps(state) {
return {
aRandomProp: Math.random()
}
}
function mapStateToProps(state) {
return {
aFilteredArray: state.anArray.filter(value => value.isTrue === true)
}
}
Creating New Objects In mapStateToProps
Use selectors, memoization and global state instead

Redux nested containers
Container
Container
Container
Component
Container
1..N
1..N
Component
Component
Component

Redux State Duplication
const state = {
users: [{ ... }],
selectedUser: {
id: 1,
name: 'Alyosha',
start: startTime,
end: endTime
},
numberOfUsers: 10,
}
Often we have a piece of the state which can be computed from another

React state
Redux

(link)
Redux doesn't solve any problem. It just creates a new problem by giving you an abstract box. And what to store is that box - its your problem.
Dan Abramov
An antipattern is just like a pattern, except that instead of a solution it gives something that looks superficially like a solution but isn't one.
Andrew Koenig (C Traps and Pitfalls)


No encapsulation
Different lifecycle

Global store is a singleton
Problems with this global store
variables visible to all the other components, even components that don’t need to know about this prop
We must manually keep cleaning the store from garbage of old components that already left the screen
but a component may have many instances, singletons are most of the time considered an anti-pattern

Don't use Redux if you wasting much CPU time or RAM resources on maintaining the immutability
Don't use redux if your application using it mainly for caching fetched resources


Don't use redux if your app mainly consists of complex forms

Don't use Redux if your containers are mostly independent
Redux Google trend worldwide for the last year
October 2019
October 2020
25%
50%
75%
100%
25%
Why the popularity has decreased?
Learning curve
Boilerplate code
Performance
Central store
No built-in way to handle side-effects
State of JS 2020

Should we stop using Redux?


Is it dead ?
Use react features/hooks instead ?

Use Redux when
You need a single source of truth
You want to maintain an undo history
You need a serializable state/actions
Travel between the state history in development
Provide alternative UI without disturbing too much of the business logic
Otherwise...

Which library to use INSTEAD??

Small projects, without a reasonable amount of data, that is changing over time

Built-in features into your view lib/framework
Mostly keeping GraphQL data

Apollo
Relay
Medium-big projects with wide model and many async updates
MobX
Big projects with long support and big teams and with good predictability
Redux
MST
Projects with predictable model transitions and good reliability


JS Community
Questions

JS Community
Quiz time!



Join http://kahoot.it/ or use the QR code!
Thank You

JS Community

Redux
By Gergely Horváth
Redux
- 188