React:Redux简介
Redux
一、概念
1. 解决什么问题?
2. 基本概念
- Redux主要作用就是统一状态管理,将分散在各个组件中的状态全部放在统一的store对象中进行管理,适用于状态特别分散、状态共用较多、状态传递较深的情形。
- Redux 是一个提供可预测化状态管理的容器,主要包含store,reducer,action
① 应用中的 state 以对象树的形式存储在 store 中
② state是只读的,惟一改变 state 的方法就是触发 action
③ action 是一个用于描述已发生事件的普通对象
④ 通过 dispatch action来改变 state,描述 action如何改变 state 的函数叫 reducer
3. 分解
- action
可参考action设计规范, type,payload,error.meta,其中 type 是必须的
异步action,通过中间件实现 - reducer
reducer必须是纯函数
可以拆分成多个reducer, 通过combineReducers合并 - store
单一Store
根据reducer创建 store.createStore(reducer,initialState)
二、Redux工作流程
1. 图示
2. 步骤分解
- 用户发出 Action
store.dispatch(action);
- Store 自动调用 Reducer,并且传入两个参数:当前 State 和收到的 Action, Reducer 会返回新的 State
let nextState = todoApp(previousState, action);
- State 一旦有变化,Store 就会调用监听函数
// 设置监听函数 store.subscribe(listener);
- listener可以通过store.getState()得到当前状态。如果使用的是 React,这时可以触发重新渲染 View
3. redux的原则
- state 是只读的,唯一修改它的方式是 actions
- 更新的唯一方式:dispatch(action) -> reducer -> new state
- Reducer 函数必须是“纯”的 —— 不能修改它的参数,也不能有副作用(不能对函数作用域之外的变量做任何更改。不要改变函数作用域以外的变量,不要调用其他会改变的函数,也不要dispatch actions等)
三、Redux改造TodoList
- 将分散在各个组件的状态统一放在store全局对象上,这样在每个组件需要状态时可以直接引入store取出状态,避免了状态之间的多层传递
- 对state的所有操作必须通过dispatch发出action给reducer,由reducer根据action的type对state进行操作并返回新的state,这使state的改变可容易追踪和可控
- 因为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
- 说明:全局状态对象store创建和导出,它需要提供一个返回 state 的函数——reducers
- 代码
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
- 说明:
① Action对象描述你想做出的改变或者将触发的事件,它必须带有一个type 属性,为action提供type描述(说明),约定action在reducers中的匹配,这个文件就是将所有的type定义为常量,避免编写时出错
② actionCreators中定义的每个回调函数返回的action对象上都有一个type属性,用以标识每个action
③ 在界面通过store.dispatch(action)(这里的action都是从actionCreators中引入的)派发到renducers时,renducers函数是通过actions.type来判断传过来的是哪个action - 代码
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
- 说明:
① 这里定义了所有的action,通过回调函数的形式返回action对象,使用回调函数的目的是为了让界面组件可以调用
② 每个action都有一个type属性,它定义了该action的类型;同时接受一个参数,是界面组件需要的状态,由action带给reducer
③ 界面上调用这里定义的回调函数(返回一个对象,对象的第一个属性type是,第二个参数是从界面接收的参数),通过store.dispatch(action)将action派发到reducers,reducres根据action.type属性对state进行相应处理
④ action充当了界面与reducers的桥梁,将界面中组件需要的数据和对数据进行的处理传给renducers,由reducers负责更新state - 代码
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
- 说明:
① reducer 的职责是接收当前 state 和一个 action 然后返回新的 state
② 状态state以及操作状态的方法都在这里,符合了数据和操作数据的方法在同一个文件的原则
③ 根据在界面组件中通过store.dispatch(action)派发过来的action.type,匹配到相应的操作状态的方法,并根据组件传入的 参数,对state进行相应操作,将当前state直接进行替换,并合并旧的state返回给store
④ reducer是直接用新的state替换旧的state,而不是更新旧的state,就是说旧的state还是保留的;返回最新的state给界面组件,同时保留了新state和旧state存入store,使state可以回溯和方便进行时间旅行调试 - 代码
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
概念
① redux-thunk是一个中间件,需要配合redux提供的applyMiddleware一起使用
② 主要是将常规的对象类型的action扩展为可接受函数类型的action
③ 它可以让原本只支持同步方式的redux扩展为支持异步的方式
④ 操作流程- 将需要修改的state都存入到store里
- 发起一个action用来描述发生了什么,用reducers描述action如何改变state tree
- 创建store的时候需要传入reducer,真正能改变store中数据的是store.dispatch API
使用
① 安装yarn add redux redux-thunk
② 步骤1import { createStore, applyMiddleware } from 'redux'; import thunk from 'redux-thunk';
③ 步骤2
const store = createStore(rootReducer,applyMiddleware(thunk) );
④ 在actionCretors中使用
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
概念
① redux-saga 是一个用于管理 Redux 应用异步操作的中间件(又称异步 action)
② redux-saga 通过创建 Sagas 将所有的异步操作逻辑收集在一个地方集中处理,可以用来代替 redux-thunk 中间件
③ 表现形式- reducer负责处理action的stage更新
- sagas负责协调那些复杂或者异步的操作
原理
① sagas是通过generator函数来创建的
② sagas监听发起的action,然后决定基于这个action来做什么
比如:是发起一个异步请求,还是发起其他的action到store,还是调用其他的sagas 等
③ 在redux-saga中,所有的任务都通过用 yield Effects 来完成
Effects 都是简单的 javascript对象,包含了要被 saga middleware 执行的信息
④ redux-saga 为各项任务提供了各种 Effects创建器,让我们可以用同步的方式来写异步代码
⑤ 名词- put(action)
① 发起一个 action 到 store
② 创建一条 Effect 描述信息,指示 middleware 发起一个 action 到 Store
③ put 是异步的,不会立即发生 - akeEvery(actionTypes, 方法)
① 如果有对应type的action触发,就执行后面的方法
② 然后由ui组件从reducer中获取数据,并显示
- put(action)
运行
① 流程:ui组件触发action创建函数 —> action创建函数返回一个action ------> action被传入redux中间件(被 saga等中间件处理) ,产生新的action,传入reducer-------> reducer把数据传给ui组件显示 -----> mapStateToProps ------> ui组件显示
② 图示:
使用
① 安装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
简介
① Redux 官方提供的 React 绑定库, 具有高效且灵活的特性
② 把store直接集成到React应用的顶层props里面,各个子组件都能访问到顶层props
③ 示例<顶层组件 store={store}><App /> </顶层组件>
Provider组件
① 使用- 一般我们都将顶层组件包裹在Provider组件之中
- 这样的话,所有组件就都可以在react-redux的控制之下了
- 但是store必须作为参数放到Provider组件中去
② 代码
<Provider store = {store}><App /> <Provider>
这个组件的目的是让所有组件都能够访问到Redux中的数据
connect
① 使用connect(mapStateToProps, mapDispatchToProps)(MyComponent)
② 剖解
- mapStateToProps:把state映射到props中去 ,其实也就是把Redux中的数据映射到React中的props中去
- mapDispatchToProps:把各种dispatch也变成了props让你可以直接使用
React:Redux简介相关推荐
- 一个 react+redux 工程实例
在前几天的一篇文章中总结部分提到了学习过程中基础的重要性.当然,并不是不支持大家学习新的框架,这篇文章就分享一下react+redux工程实例. 一直在学习研究react.js,前前后后做了几次分享. ...
- Redux简介以及Redux应用程序中的状态更新方式
by Syeda Aimen Batool 通过Syeda Aimen Batool Redux简介以及Redux应用程序中的状态更新方式 (An intro to Redux and how sta ...
- 应用数据流状态管理框架Redux简介、设计思想、核心概念及工作流
tip:有问题或者需要大厂内推的+我脉脉哦:丛培森 ٩( 'ω' )و [本文源址:http://blog.csdn.net/q1056843325/article/details/54784109 ...
- React+Redux开发实录(一)搭建工程脚手架
React+Redux开发实录(一)搭建工程脚手架 React+Redux开发实录(二)React技术栈一览 搭建工程脚手架 准备工作 安装node 安装git 安装一款前端IDE 推荐VSCode, ...
- 基于 react, redux 最佳实践构建的 2048
前段时间 React license 的问题闹的沸沸扬扬,搞得 React 社区人心惶惶,好在最终 React 团队听取了社区意见把 license 换成了 MIT.不管 React license ...
- React Redux 的一些基本知识点
一.React.createClass 跟 React.Component 的区别在于后者使用了ES6的语法,用constructor构造器来构造默认的属性和状态. 1. React.createCl ...
- 【视频】React redux toolkit创建状态切片
React redux toolkit创建状态切片
- react实战项目_React实战之React+Redux实现一个天气预报小项目
引言 经过一段时间的React学习,React和Vue的开发确实有很大的不同,但是都是MVVM框架,因此上手没有很大的难度,这次用React+Redux开发一个天气预报小项目.源码地址:https:/ ...
- React+Redux仿Web追书神器
引言 由于 10 月份做的 React Native 项目没有使用到 Redux 等库,写了一段时间想深入学习 React,有个想法想做个 demo 练手下,那时候其实还没想好要做哪一个类型的,也看了 ...
- react+redux+generation-modation脚手架搭建一个todolist
TodoList 1. 编写actions.js 2. 分析state 试着拆分成多个reducer 3. 了解store 4. 了解redux数据流生命周期 5. 分析容器组件和展示组件 搞清楚,数 ...
最新文章
- Android TextView 在strings 里面 实现换行
- 微信小程序让屏幕自动向下滚动
- GCF_000238955.2 Maylandia zebra 斑马拟丽鱼 Scaffold
- HASH Partitioning--转载
- python里面print是什么意思_python里print是什么意思
- 大数据学习——mapreduce共同好友
- linux内存源码分析 - 内存回收(匿名页反向映射)
- 简单理解Binder机制的原理
- 【推荐】区块链技术及行业应用资料合集
- 双目视觉的CALIB_CHECK_COND报错到底是个啥?
- 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明)(热身赛) C-Statues 题解【dp】【动态规划】
- 学霸是怎样炼成的?学了那么多还一无是处?如何克服学习阻力?一件枯燥讨厌的事但必须要做?内心强大的主观改造 自我加速(学以致用)与环境加速(学习型组织)
- dmitry -iwnse yuming
- 阅读类APP开发的好处有哪些
- 计算机暑期学校心得,暑期学校培训心得体会(通用12篇)
- 用计算机技术辅助语文教学,计算机技术相关毕业论文致谢,关于计算机辅助语文教学相关论文范文文献...
- JS 报错getElementsByClassName.appendChild报错“Uncaught TypeError: s.appendChild is not a function”
- 有四个整数a,b,c,d由键盘输入,输出其中最大的数 c语言编程怎么写
- JS数组扁平化flat,reduce等六种方式实现
- ERP-非财务人员的财务培训教(二)------如何评价公司/部门经营业绩