Redux ---- Tutorial Part
Reference: Redux官网
What?
Redux is a pattern and library for managing and updating application state, using events called "actions". It serves as a centralized store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a predictable fashion.
Redux是一个用来管理以及更新一个应用中的状态的工具库。
Why?
Redux helps you manage "global" state - state that is needed across many parts of your application. Redux make it easier to understand when, where, why, and how the state in your application is being updated, and how your application logic will behave when those changes occur.
Redux帮助你管理“全局”状态,并且使状态管理变得更简单,我们能够理解我们应用更新的时机、地点、原因以及如何进行更新和发生什么变化。
When?
Redux is more useful when:
- You have large amounts of application state that are needed in many places in the app
- The app state is updated frequently over time
- The logic to update that state may be complex
- The app has a medium or large-sized codebase, and might be worked on by many people
Terms & Conceptes
State Management
One way to solve “sharing state across components” is to extract the shared state from the components, and put states into a centralized location outside the component tree.
This is the basic idea behind Redux: a single centralized place to contain the global state in your application, and specific patterns to follow when updating that state to make the code predictable.
将跨组件共享的状态抽到一个集中的对象中,脱离于组件树之外,并且为了让状态具有可预测性,需要遵循一定的更新状态的规范。
Immutability
Redux expects that all state updates are done immutably
In order to update values immutably, your code must make copies of existing objects/arrays, and then modify the copies.
Redux期望以一种不可变的方式来更新它所管理的所有状态。
因此当我们要进行状态变更的时候,我们必须以一种将先前状态做一份拷贝,然后修改这个拷贝的方式来进行状态变更。
const arr = ['a', 'b']
// make a copy of the original array:
const arr3 = arr.slice()
// or
const arr3 = [...arr]
// and mutate the copy:
arr3.push('c')
Actions
An action is a plain JavaScript object that has a
typefield. You can think of an action as an event that describes something that happened in the application.The
typefield should be a string that gives this action a descriptive name.An action object can have other fields with additional information about what happened. By convention, we put that information in a field called
payload.
一个action就是一个普通的、拥有type属性的对象,可以理解为一个用来描述某个动作的事件。
type属性应该具有简明扼要的特点,用以描述这个action。
除此之外,一个action根据不同情况还可能有其他属性,通常来说,我们将这个action额外的信息赋值给payload这个属性。
一个典型的action如下:
const addTodoAction = {
type: 'todos/todoAdded',
payload: 'Buy milk'
}
Action Creator
An action creator is a function that creates and returns an action object. We typically use these so we don't have to write the action object by hand every time:
Action Creator简单来说就是用来创建一个action对象的函数,之所以需要它是因为凭借这个函数,我们不需要自己手动重复去声明一个相同的action。
一个典型的Action Creator如下:
const addTodo = text => {
return {
type: 'todos/todoAdded',
payload: text
}
}
Reducers
A reducer is a function that receives the current
stateand anactionobject, decides how to update the state if necessary, and returns the new state:(state, action) => newState. You can think of a reducer as an event listener which handles events based on the received action (event) type.Reducers must always follow some specific rules:
- They should only calculate the new state value based on the
stateandactionarguments- They are not allowed to modify the existing
state. Instead, they must make immutable updates, by copying the existingstateand making changes to the copied values.- They must not do any asynchronous logic, calculate random values, or cause other "side effects"
reducer是一个用来决定如何去更新状态并且返回新状态的一个函数,它接受两个参数,第一个是当前状态,第二个是一个action对象。reducer可以理解为根据不同的action的type,来进行一个不同的事件处理的一个方法。
值得注意的是,reducer的编写必须遵循一下几个规范:
- 新的state的结果只能基于先前的state以及action的属性(包括payload等)计算得出
- 新的state必须是以“不可变”的方式返回,简单来说就是不能在原有的state上进行更改并返回
- reducer不能包含任何副作用(异步逻辑,随机数等)
Store
The current Redux application state lives in an object called the store .
The store is created by passing in a reducer, and has a method called
getStatethat returns the current state value:
store是redux所要管理的状态集中存放的地方,通过传递reducer以及特定API来创建,并且一个store有getState的方法来获取当前store中state的值。
import { configureStore } from '@reduxjs/toolkit'
const store = configureStore({ reducer: counterReducer })
console.log(store.getState())
// {value: 0}
Dispatch
The Redux store has a method called
dispatch. The only way to update the state is to callstore.dispatch()and pass in an action object. The store will run its reducer function and save the new state value inside, and we can callgetState()to retrieve the updated value
store除了上文提到的拥有getState方法,还有一个dispatch方法,它接受一个参数,参数类型是action对象。这是唯一用来更新state的方式! 调用dispatch之后,store会执行它的reducer来处理状态变更,然后将新state更新保存到store中。
// Action Creator
const increment = () => {
return {
type: 'counter/increment'
}
}
store.dispatch(increment())
console.log(store.getState())
// {value: 1}
Selectors
Selectors are functions that know how to extract specific pieces of information from a store state value. As an application grows bigger, this can help avoid repeating logic as different parts of the app need to read the same data
Selectors是一系列用来返回一个store中特定state的函数,它的作用是当我们的应用变得越来越庞大,通过编写Selectors来避免重复的state获取逻辑。
const selectCounterValue = state => state.value
const currentValue = selectCounterValue(store.getState())
console.log(currentValue)
// 1
Redux Data Flow
one-way data flow: which describes this sequence of steps to update the app:
- State describes the condition of the app at a specific point in time
- The UI is rendered based on that state
- When something happens (such as a user clicking a button), the state is updated based on what occurred
- The UI re-renders based on the new state
For Redux specifically, we can break these steps into more detail:
Initial setup:
- A Redux store is created using a root reducer function
- The store calls the root reducer once, and saves the return value as its initial
state- When the UI is first rendered, UI components access the current state of the Redux store, and use that data to decide what to render. They also subscribe to any future store updates so they can know if the state has changed.
Updates:
- Something happens in the app, such as a user clicking a button
- The app code dispatches an action to the Redux store, like
dispatch({type: 'counter/increment'})- The store runs the reducer function again with the previous
stateand the currentaction, and saves the return value as the newstate- The store notifies all parts of the UI that are subscribed that the store has been updated
- Each UI component that needs data from the store checks to see if the parts of the state they need have changed.
- Each component that sees its data has changed forces a re-render with the new data, so it can update what's shown on the screen
单向数据流模式:
- state描述了应用在某一个时间节点的状态信息
- 基于第一点中的state来渲染UI
- 当事件发生导致了state的更新
- 基于变更后的state来重新渲染UI
图源:redux官网教程
对于Redux来说,这个模式可以更加详细一些:
-
store初始化
- store由一个root reducer来创建
- store先调用一遍root reducer来作为一个初始化的状态值
- 初次渲染的时候,组件从store中获取到当前的状态信息,进行渲染,同时,组件订阅了store的更新,以便状态跟新时进行重新渲染
-
store更新
- 利用store上的dispatch方法来派发一个action
- store重新调用reducer,reducer会基于当前的state以及action来计算出最新的state并返回给store进行保存
- store通知先前那些订阅过变更的组件
- 组件基于新的state数据进行重新渲染
图源:redux官网