Redux in Action

Part Two: Scable Redux Application

  • Framework intuitive space

The space the framework was built to solve

  • Framework negative space

The space that framework doesn't solve or have an opinion on

The perfect is the enemy of the good.

Splitting Up Reducer

  • Store
  • Action
  • Reducer

store

action

reducer

Splitting Up Reducer

One Fat Reducer VS. Splitted Thin Reducers

Splitting Up Reducer

Problems & Solutions:

  • Separating Data Handling by Domain
  • Combining Reducers by Slice with combineReducers
  • Sharing data between slice reducers
  • Boilerplate code

Get necessary data in action creators, and pass the data through actions.

Use high order functions to generate reducers.

  • Using slice reducers with ImmutableJS

Normalizing State Shape

Duplicated and Nested Structure

  • Updating a piece of duplicated data is difficult
  • Reducer logic in a deep nested state tree is complicated
  • Performance issues

Data Normalizing

Using 'byId and allIds' Pattern

  • Use 'byId' to store entities
  • Use 'allIds' to indicate ordering

Data Normalizing

Using ImmutableJS Record to Validate Entity Shape

  • Entities becomes self-documenting
  • Only the fileds in the record defination can be set

Data Normalizing

  • Each type of data gets its own "table" in the state.
  • Each "data table" should store the individual items in an object, with the IDs of the items as keys and the items themselves as the values.
  • Any references to individual items should be done by storing the item's ID.
  • Arrays of IDs should be used to indicate ordering.

Data Normalizing

Problems & Solutions:

  • More components are connected and each component is responsible for looking up its own data
  • State need to be computed rather get from the store directly

Use selectors to encapsulate the state shape and make the selecting reuseable.

Simply pass item IDs to connected children is a good pattern for optimizing UI performance

ImmutableJS

Pros:

Cons:

  • Guaranteed immutability
  • Rich API
  • Performance
  • Difficult to interoperate with
  • Once used, Immutable.JS will spread throughout your codebase
  • Difficult to debug

ImmutableJS

  • Never mix plain JavaScript objects with ImmutableJS
  • Make your entire Redux state tree an ImmutableJS object
  • Limit your use of toJS()
  • Never use toJS() in mapStateToProps()
  • Your selectors should return ImmutableJS objects
  • Use ImmutableJS objects in your connected components

Selectors

Encapsulating the Redux State Tree

  • Wrting
  • Reading

Reducersaction creators encapsulate the writing to the redux state tree.

Reading from the redux state tree is scattered through mapStateToProps(), action creators, sagas and tests. It's hard to update the state shape.

Use selectors to encapsulate the reading from the redux state tree.

store

reducer

Redux

state

action

UI

DOM Event 

Network 

……

Selectors

Reading state

Reading state

Selectors

state.todos

selectAllTodos(state)

state.todos.filter((todo) => !todo.complete).length

selectActiveTodosCount(state)

Selectors

Using Reselect to Compose Selectors and Memorize the Results

Data caching

  • 'getSomethingIfNeeded' Pattern
  • Using memorized api request

Naming action creators, thunks or sagas with 'getSomethingIfNeeded' pattern

Business Logic

  • Components
  • Action Creators(Redux-Thunk)
  • Reducers
  • Sagas
  • validation, verification, authorization
  • transformation, augmentation, applying defaults
  • processing — asynchronous things

Where to put business logic

×

×

Business Logic

Commands and Events

  • LOAD_USER is a command
  • USER_LOADED is a event

Commands:

  • What to do
  • Expected result
  • Only one specified receiver

Events:

  • What happened
  • No expected result
  • Don't care about receivers
  • Immutable

Business Logic

  • Components

Where to put business logic

×

  • Keep components as pure as possible
  • Components are responsible for presentation
  • Components publishes events to trigger business logic
  • Not for resuablity, but for simplicity - easy to modify and debug

Business Logic

  • Reducers

Where to put business logic

×

  • Reducers need to be pure (synchronous、no side effects)
  • Reducers are responsible for state updating

Business Logic

  • Action Creators(Redux-Thunk)

Where to put business logic

  • What is a thunk

Business Logic

  • Action Creators(Redux-Thunk)

Where to put business logic

  • Access global state esaily
  • Not easy to control complicated async flow
  • Simple and focused

Business Logic

  • Sagas

Where to put business logic

A saga is

  • A piece of code which runs in the background
  • Watching for dispatched actions
  • May perform some async calls (or synchronous impure calls like browser storage) and can dispatch other actions to the store.

Business Logic

  • Sagas

Where to put business logic

  • Components do not perform any business logic but only dispatch actions to notify what happened
  • A saga can also act as a decoupling point between 2 parts of the UI

Business Logic

store

reducer

Redux

state

action

UI

DOM Event 

Network 

……

Business Logic

store

reducer

Redux

state

action

UI

DOM Event 

Network 

……

action

Saga

Business Logic

Saga

Worker1

Worker2

Worker3

action

action

Task

Result

Task

Result

Task

Result

Business Logic

Generator and Runner

Redux in Action - Scable Redux Application

By yiliang_wang

Redux in Action - Scable Redux Application

  • 178