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'; // 存TODO
    export const CHANGE_TODO_ITEM = 'change_todo_item'; // 修改一条TODO的选中状态
    export const DEL_TODO_ITEM = 'del_todo_item'; //删除一条TODO
    export const ADD_TODO_ITEM = 'add_todo_item'; //添加一条TODO
    export const DEL_FINISHED_TODO_ITEM = 'del_finished_todo_item'; //删除所有已经完成的TODO
    export 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. 存Todo
    export 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进行相应操作,并返回新的state
    export default (state = defaultState, action)=>{console.log(state, action);// 1. 存所有的Todoif(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.jsexport const store = createStore(combineReducers({...reducerAll}),               // 合并reducerwindow.devToolsExtension ? window.devToolsExtension() : undefined,    // dev-toolsapplyMiddleware(sagaMiddleware)                 // 中间件,加载sagaMiddleware
    )sagaMiddleware.run(rootSaga)                        // 执行rootSaga
    

    ③ 界面配置

三、react-redux

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

    <顶层组件 store={store}><App />
    </顶层组件>
    
  2. Provider组件
    ① 使用

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

    ② 代码

    <Provider store = {store}><App />
    <Provider>
    

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

  3. connect
    ① 使用

    connect(mapStateToProps, mapDispatchToProps)(MyComponent)
    

    ② 剖解

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

React:Redux简介相关推荐

  1. 一个 react+redux 工程实例

    在前几天的一篇文章中总结部分提到了学习过程中基础的重要性.当然,并不是不支持大家学习新的框架,这篇文章就分享一下react+redux工程实例. 一直在学习研究react.js,前前后后做了几次分享. ...

  2. Redux简介以及Redux应用程序中的状态更新方式

    by Syeda Aimen Batool 通过Syeda Aimen Batool Redux简介以及Redux应用程序中的状态更新方式 (An intro to Redux and how sta ...

  3. 应用数据流状态管理框架Redux简介、设计思想、核心概念及工作流

    tip:有问题或者需要大厂内推的+我脉脉哦:丛培森 ٩( 'ω' )و [本文源址:http://blog.csdn.net/q1056843325/article/details/54784109 ...

  4. React+Redux开发实录(一)搭建工程脚手架

    React+Redux开发实录(一)搭建工程脚手架 React+Redux开发实录(二)React技术栈一览 搭建工程脚手架 准备工作 安装node 安装git 安装一款前端IDE 推荐VSCode, ...

  5. 基于 react, redux 最佳实践构建的 2048

    前段时间 React license 的问题闹的沸沸扬扬,搞得 React 社区人心惶惶,好在最终 React 团队听取了社区意见把 license 换成了 MIT.不管 React license ...

  6. React Redux 的一些基本知识点

    一.React.createClass 跟 React.Component 的区别在于后者使用了ES6的语法,用constructor构造器来构造默认的属性和状态. 1. React.createCl ...

  7. 【视频】React redux toolkit创建状态切片

    React redux toolkit创建状态切片

  8. react实战项目_React实战之React+Redux实现一个天气预报小项目

    引言 经过一段时间的React学习,React和Vue的开发确实有很大的不同,但是都是MVVM框架,因此上手没有很大的难度,这次用React+Redux开发一个天气预报小项目.源码地址:https:/ ...

  9. React+Redux仿Web追书神器

    引言 由于 10 月份做的 React Native 项目没有使用到 Redux 等库,写了一段时间想深入学习 React,有个想法想做个 demo 练手下,那时候其实还没想好要做哪一个类型的,也看了 ...

  10. react+redux+generation-modation脚手架搭建一个todolist

    TodoList 1. 编写actions.js 2. 分析state 试着拆分成多个reducer 3. 了解store 4. 了解redux数据流生命周期 5. 分析容器组件和展示组件 搞清楚,数 ...

最新文章

  1. Android TextView 在strings 里面 实现换行
  2. 微信小程序让屏幕自动向下滚动
  3. GCF_000238955.2 Maylandia zebra 斑马拟丽鱼 Scaffold
  4. HASH Partitioning--转载
  5. python里面print是什么意思_python里print是什么意思
  6. 大数据学习——mapreduce共同好友
  7. linux内存源码分析 - 内存回收(匿名页反向映射)
  8. 简单理解Binder机制的原理
  9. 【推荐】区块链技术及行业应用资料合集
  10. 双目视觉的CALIB_CHECK_COND报错到底是个啥?
  11. 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明)(热身赛) C-Statues 题解【dp】【动态规划】
  12. 学霸是怎样炼成的?学了那么多还一无是处?如何克服学习阻力?一件枯燥讨厌的事但必须要做?内心强大的主观改造 自我加速(学以致用)与环境加速(学习型组织)
  13. dmitry -iwnse yuming
  14. 阅读类APP开发的好处有哪些
  15. 计算机暑期学校心得,暑期学校培训心得体会(通用12篇)
  16. 用计算机技术辅助语文教学,计算机技术相关毕业论文致谢,关于计算机辅助语文教学相关论文范文文献...
  17. JS 报错getElementsByClassName.appendChild报错“Uncaught TypeError: s.appendChild is not a function”
  18. 有四个整数a,b,c,d由键盘输入,输出其中最大的数 c语言编程怎么写
  19. JS数组扁平化flat,reduce等六种方式实现
  20. ERP-非财务人员的财务培训教(二)------如何评价公司/部门经营业绩

热门文章

  1. 4. HTTP Status Code
  2. 60. MySQLi 扩展拾遗
  3. 17. JavaScript Math(算数)对象
  4. 1.Magento的配置系统
  5. Docker在测试领域的应用
  6. can't find '__main__' module in '.'
  7. 《第一本docker书》第4章 使用docker镜像和仓库 读书笔记
  8. uva11992-Fast Matrix Operations(区间增值、改值)
  9. 445port入侵详细解释
  10. matlab求最大公约数和最小公倍数