Redux
- 概念:redux是react最常用的集中状态管理工具,类似于Vue中的Pinia(vuex),可以独立于框架运行
- 作用:通过集中管理的方式管理应用的状态
Redux快速体验
- 不和任何框架绑定,不使用任何构建工具,使用纯Redux实现计数器
- 使用步骤:
- 定义一个reducer函数 (根据当前想要做的修改返回一个新的状态)
- 使用createStore方法传入 reducer函数 生成一个store实例对象
- 使用store实例的 subscribe 方法订阅数据的变化 (数据一旦变化,可以得到通知)
- 使用store实例的 dispatch 方法提交action对象 触发数据变化 (告诉reducer你想怎么改数据)
- 使用store实例的 getState方法 获取最新的状态数据更新到视图中
Redux管理数据流程梳理
为了职责清晰,数据流向明确,Redux把整个数据修改的流程分为了三个核心概念,分别是: state,action,和reducer
- state —— 一个对象 存放着我们管理的数据状态
- action—— 一个对象 用来描述你想怎么改数据
- reducer—— 一个函数 更具action的描述生成一个新的state
Redux 在 React中使用
在react中使用redux,官方要求安装两个其他插件 - Redux Toolkit 和 react-redux
- Redux Toolkit (RTK) - 官方推荐编写Redux逻辑的方式,是一套工具的集合集,简化书写方式
- react-redux - 用来 链接 redux 和 react 组件的中间件
- 官方推荐的使用 React 和 Redux 创建新应用的方式是使用 官方 Redux+JS 模版或 Redux+TS 模板,它基于 Create React App,利用了 Redux Toolkit 和 Redux 与 React 组件的集成.
# Redux + Plain JS template
npx create-react-app my-app --template redux
# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript
深入浅出Redux
基础示例
应用的整体全局状态以对象树的方式存放于单个store。唯一改变状态树 (state tree) 的方法是创建action,一个描述发生了什么的对象,并将其dispatch 给 store。要指定状态树如何相应action来进行更新,你可以编写纯reducer函数,这些函数根据旧state 和 action 来计算新的state
import { createStore } from 'redux'
/**
* 这是一个 reducer 函数:接受当前 state 值和描述“发生了什么”的 action 对象,它返回一个新的 state 值。
* reducer 函数签名是 : (state, action) => newState
*
* Redux state 应该只包含普通的 JS 对象、数组和原语。
* 根状态值通常是一个对象。 重要的是,不应该改变 state 对象,而是在 state 发生变化时返回一个新对象。
*
* 你可以在 reducer 中使用任何条件逻辑。 在这个例子中,我们使用了 switch 语句,但这不是必需的。
*
*/
function counterReducer (state = {value: 0}, action) {
switch (action.type) {
case 'counter/incremented':
return { value: state.value + 1 }
case 'counter/decremented':
return { value: state.value - 1 }
default:
return state
}
}
// 创建一个包含应用程序 state 的 Redux store.
// 它的 API 有 {subscribe, dispatch, getState}
let store = createStore(counterReducer);
// 你可以使用subscribe() 来更新 UI 以响应 state 的更改
// 通常你会使用视图绑定库 (例如 React Redux) 而不是直接使用 subscribe()。
// 可能还有其他用例对subscribe 也有帮助
store.subscribe(() => console.log(state.getState()))
// 改变内部状态的唯一方法是 dispatch 一个action。
// 这些 action 可以被序列化,记录或储存,然后再重放
store.dispatch({ type: 'counter/incremented' })
// {value: 1}
store.dispatch({ type: 'counter/incremented' })
// {value: 2}
store.dispatch({ type: 'counter/decremented' })
// {value: 1}
你需要使用action这个普通对象来描述发生了什么,而不是直接改变state。然后,编写一个名为reducer的特殊函数,来决定如何基于action来更新整个应用的状态树。
在典型的Redux应用中,只有一个store以及一个根reducer函数。随着应用程序的增长,你可以将根reducer拆分为较小的reducer,分别在状态树的不同部分上进行。这就像React应用程序只有一个根组件一样,但是它是由许多小组件组成的。
对于简单的计数器应用来说,这种架构看起来过度设计,但是这种模式的优点在于它可以很好地扩展到大型和复杂的应用程序。还可以基于此设计出功能非常强大的开发者工具,因为可以跟踪每个 action 以及状态变更。你可以记录用户会话并仅通过重播每个 action 来重现它们。
Redux Toolkit示例
Redux Tookit 简化了编写Redux逻辑和设置store的过程。使用 Redux Toolkit相同逻辑如下所示:
import { createSlice, configureStore } from '@reduxjs/toolkit'
const counterSlice = createSlice({
// 给仓库起一个独一无二的名字
name: 'counter',
// 初始化状态的值
initialState: {
value: 0
},
// 简化了reducer函数
reducers: {
incremented: state => {
// Redux Toolkit 允许在 reducers 中编写 'mutating' 逻辑。
// 它实际上并没有改变state,因为使用的是 Immer 库,检测到“草稿 state” 的变化并产生一个全新基于这些更改不可变的 state
state.value +=1
},
decremented: state => {
state.value -= 1
}
}
})
// 按需从actions对象中导出 更改状态的方式
export const { incremented, decrenebted } = counterSlice.actions
// 创建store实例,挂载reducer函数
const store = configureStore({
reducer: counterSlice.reducer
})
// 可以订阅 store
store.subscribe(() => console.log(store.getState()))
// 将我们所创建的 action 对象传递给 `dispatch`
store.dispatch(incremented())
// {value: 1}
store.dispatch(incremented())
// {value: 2}
store.dispatch(decremented())
// {value: 1}
Redux Toolkit 包含什么
- configureStore():封装了createStore,简化配置项,提供一些现成的默认配置项。它可以自动组合 slice 的 reducer,可以添加任何 Redux 中间件,默认情况下包含
redux-thunk
,并开启了 Redux DevTools 扩展。 - createSlice():接收一组reducer函数的对象,一个slice切片名和初始状态 initial state,并自动生成具有相应action creator 和 action type 的slice reducer
- createReducer():帮你将action type 映射到 reducer 函数,而不是编写 switch…case语句。另外,它会自动使用immer库来让你使用普通的 mutable 代码编写更简单的immutable更新,例如
state.todos[3].completed = true
- createAction():生成给定 action type 字符串的 action creator函数。该函数本身已定义了
toString()
,因此可以代替常量类型使用 - createAsyncThunk:接收一个 action type 字符串和一个返回值为 promise 的函数, 并生成一个 thunk 函数,这个 thunk 函数可以基于之前那个 promise ,dispatch 一组 type 为
pending/fulfilled/rejected
的 action。 - createEntityAdapter:生成一系列可复用的 reducer 和 selector,从而管理 store 中的规范化数据。
- createSelector来源于 Reselect 库,重新 export 出来以方便使用。
Redux Toolkit 注入 React
Redux Toolkit包含一个组件,它使Redux store对应用程序的其余部分可用:
import React from 'react'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import store from './store'
import App from './App'
// As of React 18
const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
<Provider store={store}>
<App />
</Provider>
)