React:Redux简介
发布日期:2021-06-30 15:49:26 浏览次数:3 分类:技术文章

本文共 9967 字,大约阅读时间需要 33 分钟。

Redux

一、概念

1. 解决什么问题?

在这里插入图片描述

2. 基本概念

  1. Redux主要作用就是统一状态管理,将分散在各个组件中的状态全部放在统一的store对象中进行管理,适用于状态特别分散、状态共用较多、状态传递较深的情形。
  2. Redux 是一个提供可预测化状态管理的容器,主要包含store,reducer,action
    ① 应用中的 state 以对象树的形式存储在 store 中
    ② state是只读的,惟一改变 state 的方法就是触发 action
    ③ action 是一个用于描述已发生事件的普通对象
    ④ 通过 dispatch action来改变 state,描述 action如何改变 state 的函数叫 reducer

3. 分解

  1. action
    可参考action设计规范, type,payload,error.meta,其中 type 是必须的
    异步action,通过中间件实现
  2. reducer
    reducer必须是纯函数
    可以拆分成多个reducer, 通过combineReducers合并
  3. store
    单一Store
    根据reducer创建 store.createStore(reducer,initialState)

二、Redux工作流程

1. 图示

在这里插入图片描述

2. 步骤分解

  1. 用户发出 Action
    store.dispatch(action);
  2. Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action, Reducer 会返回新的 State
    let nextState = todoApp(previousState, action);
  3. State 一旦有变化,Store 就会调用监听函数
    // 设置监听函数store.subscribe(listener);
  4. listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View

3. redux的原则

  1. state 是只读的,唯一修改它的方式是 actions
  2. 更新的唯一方式:dispatch(action) -> reducer -> new state
  3. Reducer 函数必须是“纯”的 —— 不能修改它的参数,也不能有副作用(不能对函数作用域之外的变量做任何更改。不要改变函数作用域以外的变量,不要调用其他会改变的函数,也不要dispatch actions等)

三、Redux改造TodoList

  1. 将分散在各个组件的状态统一放在store全局对象上,这样在每个组件需要状态时可以直接引入store取出状态,避免了状态之间的多层传递
  2. 对state的所有操作必须通过dispatch发出action给reducer,由reducer根据action的type对state进行操作并返回新的state,这使state的改变可容易追踪和可控
  3. 因为store是全局的,因此子组件不需要组件向父组件开放过多的接口(不需要传入那么多的变量给prop)

四、TodoList改造步骤

1. 目录结构规划

src |

     -| commponents
     -| store
App.js
index.css
index.js
store |
        -| index.js
        -| reducers.js
        -| actionCreators
        -| actionTypes
commponents |
                      -| Foot.jsx
                      -| Item.jsx
                      -| List.jsx
                      -| Top.jsx

2. store/index.js

  1. 说明:全局状态对象store创建和导出,它需要提供一个返回 state 的函数——reducers
  2. 代码
    import {
    createStore, applyMiddleware, compose} from 'redux'import reducers from './reducers'import ReduxThunk from 'redux-thunk'// 处理redux-thunk的兼容问题const composeEnhancers = typeof window === 'object' && window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
    }) : compose;const enhancer = composeEnhancers( applyMiddleware(ReduxThunk));//创建store状态管理对象const store = createStore(reducers, enhancer);export default store;

3. store/actionTypes

  1. 说明:
    ① Action对象描述你想做出的改变或者将触发的事件,它必须带有一个type 属性,为action提供type描述(说明),约定action在reducers中的匹配,这个文件就是将所有的type定义为常量,避免编写时出错
    ② actionCreators中定义的每个回调函数返回的action对象上都有一个type属性,用以标识每个action
    ③ 在界面通过store.dispatch(action)(这里的action都是从actionCreators中引入的)派发到renducers时,renducers函数是通过actions.type来判断传过来的是哪个action
  2. 代码
    export const GET_ALL_ITEM = 'get_all_item'; // 存TODOexport const CHANGE_TODO_ITEM = 'change_todo_item'; // 修改一条TODO的选中状态export const DEL_TODO_ITEM = 'del_todo_item'; //删除一条TODOexport const ADD_TODO_ITEM = 'add_todo_item'; //添加一条TODOexport const DEL_FINISHED_TODO_ITEM = 'del_finished_todo_item'; //删除所有已经完成的TODOexport const IS_CHECKED_ALL_TODO_ITEM = 'is_checked_all_todo_item'; //删除所有已经完成的TODO

4. store/actionCreators.js

  1. 说明:
    ① 这里定义了所有的action,通过回调函数的形式返回action对象,使用回调函数的目的是为了让界面组件可以调用
    ② 每个action都有一个type属性,它定义了该action的类型;同时接受一个参数,是界面组件需要的状态,由action带给reducer
    ③ 界面上调用这里定义的回调函数(返回一个对象,对象的第一个属性type是,第二个参数是从界面接收的参数),通过store.dispatch(action)将action派发到reducers,reducres根据action.type属性对state进行相应处理
    ④ action充当了界面与reducers的桥梁,将界面中组件需要的数据和对数据进行的处理传给renducers,由reducers负责更新state
  2. 代码
    import {
    GET_ALL_ITEM, CHANGE_TODO_ITEM, DEL_TODO_ITEM, ADD_TODO_ITEM, DEL_FINISHED_TODO_ITEM, IS_CHECKED_ALL_TODO_ITEM} from './actionTypes'// 1. 存Todoexport const getAllItemAction = (todos)=>({
    type: GET_ALL_ITEM, todos});// 2. 单个TODO选中与否export const getChangeItemFinishedAction = (todoId, flag)=>({
    type: CHANGE_TODO_ITEM, todoId, flag});// 3. 单个TODO删除export const getDelItemAction = (todoId)=>({
    type: DEL_TODO_ITEM, todoId});// 4. 添加一条记录export const getAddItemAction = (todo)=>({
    type: ADD_TODO_ITEM, todo});// 5. 删除所有已经完成的记录export const getRemoveFinishedItemAction = ()=>({
    type: DEL_FINISHED_TODO_ITEM});// 6. 全选与非全选export const getIsCheckedAllAction = (flag)=>({
    type: IS_CHECKED_ALL_TODO_ITEM, flag});

5. store/reducers

  1. 说明:
    ① reducer 的职责是接收当前 state 和一个 action 然后返回新的 state
    ② 状态state以及操作状态的方法都在这里,符合了数据和操作数据的方法在同一个文件的原则
    ③ 根据在界面组件中通过store.dispatch(action)派发过来的action.type,匹配到相应的操作状态的方法,并根据组件传入的 参数,对state进行相应操作,将当前state直接进行替换,并合并旧的state返回给store
    ④ reducer是直接用新的state替换旧的state,而不是更新旧的state,就是说旧的state还是保留的;返回最新的state给界面组件,同时保留了新state和旧state存入store,使state可以回溯和方便进行时间旅行调试
  2. 代码
    import {
    GET_ALL_ITEM, CHANGE_TODO_ITEM, DEL_TODO_ITEM, ADD_TODO_ITEM, DEL_FINISHED_TODO_ITEM, IS_CHECKED_ALL_TODO_ITEM} from './actionTypes'// 初始状态数据const defaultState = {
    todos: [], finishedCount: 0};//根据action的type,对state进行相应操作,并返回新的stateexport default (state = defaultState, action)=>{
    console.log(state, action); // 1. 存所有的Todo if(action.type === GET_ALL_ITEM){
    const newState = JSON.parse(JSON.stringify(state)); newState.todos = action.todos; return newState; } // 2. 选中与取消选中 if(action.type === CHANGE_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state)); // 1. 遍历 let tempFinishedCount = 0; newState.todos.forEach((todo, index)=>{
    if(action.todoId === todo.id){
    todo.finished = action.flag; } if(todo.finished){
    tempFinishedCount += 1; } }); // 2. 返回一个新的状态 newState.finishedCount = tempFinishedCount; return newState; } // 3. 单个TODO删除 if(action.type === DEL_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state)); // 1. 遍历 let tempFinishedCount = 0; newState.todos.forEach((todo, index)=>{
    if(action.todoId === todo.id){
    newState.todos.splice(index, 1); } }); // 处理选中的 newState.todos.forEach((todo, index)=>{
    if(todo.finished){
    tempFinishedCount += 1; } }); // 2. 返回新状态 newState.finishedCount = tempFinishedCount; return newState; } // 4. 添加一条记录 if(action.type === ADD_TODO_ITEM){
    console.log(action); const newState = JSON.parse(JSON.stringify(state)); newState.todos.push(action.todo); return newState; } // 5. 删除所有已经完成的记录 if(action.type === DEL_FINISHED_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state)); let tempArr = []; newState.todos.forEach((todo, index)=>{
    if(!todo.finished){
    // 没有完成的任务 tempArr.push(todo); } }); // 2. 返回新状态 newState.finishedCount = 0; newState.todos = tempArr; return newState; } // 6. 全选与非全选 if(action.type === IS_CHECKED_ALL_TODO_ITEM){
    const newState = JSON.parse(JSON.stringify(state)); // 6.1. 遍历 let tempFinishedCount = 0; newState.todos.forEach((todo, index)=>{
    todo.finished = action.flag; }); // 处理选中的 newState.todos.forEach((todo, index)=>{
    if(todo.finished){
    tempFinishedCount += 1; } }); // 6.2. 返回新状态 newState.finishedCount = tempFinishedCount; return newState; } return state;}

Redux中间件

一、redux-thunk

  1. 概念

    ① redux-thunk是一个中间件,需要配合redux提供的applyMiddleware一起使用
    ② 主要是将常规的对象类型的action扩展为可接受函数类型的action
    ③ 它可以让原本只支持同步方式的redux扩展为支持异步的方式
    ④ 操作流程

    1. 将需要修改的state都存入到store里
    2. 发起一个action用来描述发生了什么,用reducers描述action如何改变state tree
    3. 创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API
  2. 使用

    ① 安装yarn add redux redux-thunk
    ② 步骤1

    import {
    createStore, applyMiddleware } from 'redux';import thunk from 'redux-thunk';

    ③ 步骤2

    const store = createStore(  rootReducer,  applyMiddleware(thunk));

    在这里插入图片描述

    ④ 在actionCretors中使用
    在这里插入图片描述

  3. redux-dev-tools和redux-thunk兼容:

    const composeEnhancers =    typeof window === 'object' &&    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?        window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({
    }) : compose;const enhancer = composeEnhancers( applyMiddleware(thunk),);

    在这里插入图片描述

二、Redux-saga

  1. 概念

    ① redux-saga 是一个用于管理 Redux 应用异步操作的中间件(又称异步 action)
    ② redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件
    ③ 表现形式

    1. reducer负责处理action的stage更新
    2. sagas负责协调那些复杂或者异步的操作
  2. 原理

    ① sagas是通过generator函数来创建的
    ② sagas监听发起的action,然后决定基于这个action来做什么
    比如:是发起一个异步请求,还是发起其他的action到store,还是调用其他的sagas 等
    ③ 在redux-saga中,所有的任务都通过用 yield Effects 来完成
    Effects 都是简单的 javascript对象,包含了要被 saga middleware 执行的信息
    ④ redux-saga 为各项任务提供了各种 Effects创建器,让我们可以用同步的方式来写异步代码
    ⑤ 名词

    1. put(action)
      ① 发起一个 action 到 store
      ② 创建一条 Effect 描述信息,指示 middleware 发起一个 action 到 Store
      ③ put 是异步的,不会立即发生
    2. akeEvery(actionTypes, 方法)
      ① 如果有对应type的action触发,就执行后面的方法
      ② 然后由ui组件从reducer中获取数据,并显示
  3. 运行

    ① 流程:ui组件触发action创建函数 —> action创建函数返回一个action ------> action被传入redux中间件(被 saga等中间件处理) ,产生新的action,传入reducer-------> reducer把数据传给ui组件显示 -----> mapStateToProps ------> ui组件显示
    ② 图示:
    在这里插入图片描述

  4. 使用

    ① 安装yarn add redux-saga
    ② 引入

    import {
    createStore,combineReducers, applyMiddleware} from 'redux';import userNameReducer from '../username/reducer.js';import createSagaMiddleware from 'redux-saga'; // 引入redux-saga中的createSagaMiddleware函数import rootSaga from './saga.js'; // 引入saga.js export const store = createStore( combineReducers({
    ...reducerAll}), // 合并reducer window.devToolsExtension ? window.devToolsExtension() : undefined, // dev-tools applyMiddleware(sagaMiddleware) // 中间件,加载sagaMiddleware)sagaMiddleware.run(rootSaga) // 执行rootSaga

    ③ 界面配置

三、react-redux

  1. 简介

    ① Redux 官方提供的 React 绑定库, 具有高效且灵活的特性
    ② 把store直接集成到React应用的顶层props里面,各个子组件都能访问到顶层props
    ③ 示例

    <顶层组件 store="{" store}>
  2. Provider组件

    ① 使用

    1. 一般我们都将顶层组件包裹在Provider组件之中
    2. 这样的话,所有组件就都可以在react-redux的控制之下了
    3. 但是store必须作为参数放到Provider组件中去

    ② 代码

    在这里插入图片描述

    这个组件的目的是让所有组件都能够访问到Redux中的数据

  3. connect

    ① 使用

    connect(mapStateToProps, mapDispatchToProps)(MyComponent)

    ② 剖解

    1. mapStateToProps:把state映射到props中去 ,其实也就是把Redux中的数据映射到React中的props中去
    2. mapDispatchToProps:把各种dispatch也变成了props让你可以直接使用
      在这里插入图片描述

转载地址:https://kaisarh.blog.csdn.net/article/details/111476228 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:React:Hook
下一篇:React:react-router

发表评论

最新留言

做的很好,不错不错
[***.243.131.199]2024年05月05日 11时59分01秒