React:Redux简介
发布日期:2021-06-30 15:49:26
浏览次数:3
分类:技术文章
本文共 9967 字,大约阅读时间需要 33 分钟。
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.jsx2. 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'; // 存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
- 说明: ① 这里定义了所有的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. 存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
- 说明: ① 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进行相应操作,并返回新的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
-
概念
① 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中获取数据,并显示
-
运行
① 流程: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.js export const store = createStore( combineReducers({ ...reducerAll}), // 合并reducer window.devToolsExtension ? window.devToolsExtension() : undefined, // dev-tools applyMiddleware(sagaMiddleware) // 中间件,加载sagaMiddleware)sagaMiddleware.run(rootSaga) // 执行rootSaga
③ 界面配置
三、react-redux
-
简介
① Redux 官方提供的 React 绑定库, 具有高效且灵活的特性 ② 把store直接集成到React应用的顶层props里面,各个子组件都能访问到顶层props ③ 示例<顶层组件 store="{" store}>
顶层组件> -
Provider组件
① 使用- 一般我们都将顶层组件包裹在Provider组件之中
- 这样的话,所有组件就都可以在react-redux的控制之下了
- 但是store必须作为参数放到Provider组件中去
② 代码
这个组件的目的是让所有组件都能够访问到Redux中的数据
-
connect
① 使用connect(mapStateToProps, mapDispatchToProps)(MyComponent)
② 剖解
- mapStateToProps:把state映射到props中去 ,其实也就是把Redux中的数据映射到React中的props中去
- mapDispatchToProps:把各种dispatch也变成了props让你可以直接使用
转载地址:https://kaisarh.blog.csdn.net/article/details/111476228 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!
发表评论
最新留言
做的很好,不错不错
[***.243.131.199]2024年05月05日 11时59分01秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
基于SSM的兼职论坛系统的设计与实现
2019-04-30
基于java的ssm框架就业信息管理系统的设计
2019-04-30
如何用同期群分析模型提升留存?(Tableau实战)
2019-04-30
2021最新 上海互联网公司排名
2019-04-30
Oracle字符串分隔符替换(替换奇数个或偶数个)
2019-04-30
Oracle 利用 UTL_SMTP 包发送邮件
2019-04-30
Oracle 的循环中的异常捕捉和处理
2019-04-30
Oracle通过pivot和unpivot配合实现行列转换
2019-04-30
Oracle的pfile和spfile的一点理解和笔记
2019-04-30
WebService的简单案例记录(Java)
2019-04-30
java实现稀疏数组及将稀疏数组存入硬盘中
2019-04-30
2021-05-18
2019-04-30
libuv实现ping包发送和接收
2019-04-30
基础架构系列篇-系统centos7安装docker+COMPOSE
2019-04-30
基础架构系列篇-NGINX部署VUE
2019-04-30
基础架构系列篇-系统centos7安装kafka
2019-04-30
基础架构系列篇-系统centos7中docker安装分布式文件存储服务minio
2019-04-30
软件质量的8个特性
2019-04-30
应届渣渣前端的艰难求职之路
2019-04-30
2021年不可错过的17种JS优化技巧(一)
2019-04-30