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

  • 129