Redux梳理总结一文通透 |
您所在的位置:网站首页 › redux使用方法 › Redux梳理总结一文通透 |
第6章:redux
一、redux理解
1. 学习文档
英文文档: https://redux.js.org/中文文档: http://www.redux.org.cn/Github: https://github.com/reactjs/redux
2. redux是什么
redux是一个专门用于做状态管理的JS库(不是react插件库)。 它可以用在react, angular, vue等项目中, 但基本与react配合使用。 作用: 集中式管理react应用中多个组件共享的状态。 安装:npm i redux 3. 什么情况下使用redux某个组件的状态,需要让其他组件可以随时拿到(共享)。 一个组件需要改变另一个组件的状态(通信)。 总体原则:能不用就不用, 如果不用比较吃力才考虑使用。 4. redux工作流程action 是 store 中唯一的数据来源,一般来说,我们会通过调用 store.dispatch 将 action 传到 store,我们需要传递的 action 是一个对象,它必须要有一个 type 值 动作的对象 包含两个属性 type:标识属性,值为字符串,唯一,必要属性data:数据类型,值类型任意,可选属性例子:{ type: 'ADD_STUDENT',data:{name: 'tom',age:18} } /* 该文件专门为Count组件生成action对象 */ import { INCREMENT, DECREMENT } from "./constant"; export const createIncrementAction = (data) => ({ type: INCREMENT, data }); export const createDecrementAction = (data) => ({ type: DECREMENT, data }); 2. reducer在 Reducer 中,我们需要指定状态的操作类型,要做怎样的数据更新,因此这个类型是必要的。reducer 会根据 action 的指示,对 state 进行对应的操作,然后返回操作后的 state 用于初始化状态加工状态 根据旧的state和action, 产生新的state的纯函数。 作为createStore的参数 代码: /* 1.该文件用于创建一个为Count组件服务的reducer,reducer的本质是一个函数 2.reducer会接受到两个参数,分别为之前的状态(preState),动作对象(action) */ import { INCREMENT, DECREMENT } from "./constant"; const initState = 0; // 初始化状态 export default function countReducer(preState = initState, action) { // console.log(preState); const { type, data } = action; switch (type) { case INCREMENT: // 加 return preState + data; case DECREMENT: // 减 return preState - data; default: return preState; } } 3. storestore 是 Redux 的核心,可以理解为是 Redux 的数据中台,我们可以将任何我们想要存放的数据放在 store中,在我们需要使用这些数据时,我们可以从中取出相应的数据。因此我们需要先创建一个 store,在 Redux 中可以使用 createStoreAPI 来创建一个store 在生产中,我们需要在 src 目录下的 redux 文件夹中新增一个 store.js 文件,在这个文件中,创建一个 store 对象,并暴露它 将state、action、reducer联系在一起的对象 如何得到此对象? import {createStore} from 'redux' import reducer from './reducers' const store = createStore(reducer)此对象的功能? getState(): 得到state dispatch(action): 分发action, 触发reducer调用, 产生新的state subscribe(listener): 注册监听, 当产生了新的state时, 自动调用 代码: /* 该文件专门用于暴露一个store对象,整个应用只有一个store对象 */ // 引入createStore import { legacy_createStore } from "redux"; // 引入为Count组件服务的reducer import countReducer from "./count_reducer"; // 暴露store export default legacy_createStore(countReducer); 三、redux核心API 1. createstore(reducer)作用:创建包含指定reducer的store对象 2. store对象作用: redux库最核心的管理对象 它内部维护着: statereducer核心方法: getState():获取当前时刻的 storedispatch(action):通过 store 中的 dispatch 方法来派生一个 action 对象给 storesubscribe(listener):subscribe方法,这个方法可以帮助我们订阅 store 的改变,只要 store发生改变,这个方法的回调就会执行具体编码: store.getState() store.dispatch({type:'INCREMENT', number}) store.subscribe(render) store.subscribe(() => { ReactDOM.render( , document.getElementById('root')) }) 3. applyMiddleware()作用:应用上基于redux的中间件(插件库) import thunk from 'redux-thunk' export default createStore(countReducer, applyMiddleware(thunk)) 4. combineReducers()作用:合并多个reducer函数 5. redux异步编程redux默认是不能进行异步处理的, 某些时候应用中需要在redux中执行异步任务(ajax, 定时器) 使用异步中间件 npm install --save redux-thunk import thunk from 'redux-thunk' export default createStore(countReducer, applyMiddleware(thunk))代码: export const createIncrementAsyncAction = (data, time) => { // 无需引入 store ,在调用的时候是由 store 调用的 return (dispatch) => { setTimeout(() => { dispatch(createIncrementAction(data)) }, time) } }注意:异步 action 不是必须要写的,完全可以自己等待异步任务的结果后再去分发同步action 采用 react-thunk 能让异步代码像同步代码一样执行,在 redux 中我们也是可以实现异步的,但是这样我们的代码中会有很多异步的细节,这不是我们想看到的,利用 react-thunk 之类的库,就能让我们只关心我们的业务 6. Redux 三大原则理解好 Redux 有助于我们更好的理解接下来的 React -Redux 第一个原则 单向数据流:整个 Redux 中,数据流向是单向的 UI 组件 —> action —> store —> reducer —> store 第二个原则 state 只读:在 Redux 中不能通过直接改变 state ,来控制状态的改变,如果想要改变 state ,则需要触发一次 action。通过 action 执行 reducer第三个原则 纯函数执行:每一个reducer 都是一个纯函数,不会有任何副作用,返回是一个新的 state,state 改变会触发 store 中的 subscribe### 四、react-redux在前面我们学习了 Redux ,我们在写案例的时候,也发现了它存在着一些问题,例如组件状态无法公用,每一个状态组件都需要通过订阅来监视,状态更新会影响到全部组件更新,面对着这些问题,React 官方在 redux 基础上提出了 React-Redux 库,专门用来简化react应用中使用redux 安装:npm i react-redux 1. 容器组件和 UI 组件UI组件 只负责 UI 的呈现,不带有任何业务逻辑 通过props接收数据(一般数据和函数) 不使用任何 Redux 的 API 一般保存在components文件夹下 容器组件 负责管理数据和业务逻辑,不负责UI的呈现 使用 Redux 的 API 一般保存在containers文件夹下 由于我们的状态可能会被很多组件使用,所以 React-Redux 给我们提供了一个 Provider 组件,可以全局注入 redux 中的 store ,只需要把 Provider 注册在根部组件即可 在 src 目录下的 index.js 文件中,引入 Provider ,直接用 Provider 标签包裹 App 组件,将 store 写在 Provider 中即可。这样我们在 App.jsx 文件中,组件无需手写指定 store ,即可使用 store ReactDOM.render( , document.getElementById("root") ); 3. connect在前面我们看到的 react-redux 原理图时,我们会发现容器组件需要给 UI 组件传递状态和方法,并且是通过 props 来传递,看起来很简单。但是,我们会发现容器组件中似乎没有我们平常传递 props 的情形。 因为UI组件是通过**connect()(UI组件)**这样的形式连接。这时候就需要继续研究一下容器组件中的唯一一个函数 connect connect 方法是一个连接器,用于连接容器组件和 UI 组件的高阶函数,它第一次执行时,接收4个参数,这些参数都是可选的,第一次执行时的四个参数:mapStateToProps 、mapDispatchToProps 、mergeProps、options,它执行的执行的结果还是一个函数,第二次执行接收一个 UI 组件参数 mapStateToProps:函数 建立了UI 组件和容器组件间的状态传递 代码:const mapStateToProps = state => ({ count: state }) 它接收 state 作为参数,并且返回一个对象,这个对象标识着 UI 组件的同名参数 返回的对象中的 key 就作为传递给 UI 组件 props 的 key,value 就作为 props 的 value UI 组件中直接通过 props 来读取 count 值 当前求和为:{this.props.count} mapDispatchToProps:函数或者对象 connect 接受的第二个参数是 mapDispatchToProps,它是用于建立 UI 组件的参数到 store.dispacth 方法的映射 我们可以把参数写成对象形式,在这里面定义 action 执行的方法,例如 jia 执行什么函数,jian 执行什么函数? 我们都可以在这个参数中定义,如下定义了几个方法对应的操作函数 { jia: createIncrementAction, jian: createDecrementAction, jiaAsync: createIncrementAsyncAction }自动调用dispatch 似乎少了点什么,我们在这里调用了函数,创建了 action 对象,但是好像 store 并没有执行 dispatch ,那是不是断了呢?执行不了呢? 其实这里 react-redux 已经帮我们做了优化,当调用 actionCreator 的时候,会立即发送 action 给 store 而不用手动的 dispatch 即connect(mapStateToProps, mapDispatchToProps)(CountUI); 4. react-redux的优化容器组件和UI组件整合一个文件 无需自己给容器组件传递store,给包裹一个即可。 使用了react-redux后也不用再自己检测redux中状态的改变了,容器组件可以自动完成这个工作。即不用写一下代码: // 监测redux中状态的改变,如果redux的状态发生了改变,那么重新渲染App组件 store.subscribe(() => { ReactDOM.render(, document.getElementById("root")); });mapDispatchToProps也可以简单的写成一个对象 一个组件要和redux“打交道”要经过哪几步? 定义好UI组件—不暴露 引入connect生成一个容器组件,并暴露,写法如下: connect( state => ({ key : value }), //映射状态 { key : xxxxxAction } //映射操作状态的方法 )(UI组件)在UI组件中通过this.props.xxxxxxx读取和操作状态 5. react-redux数据共享定义一个Pserson组件,和Count组件通过redux共享数据。 为Person组件编写:reducer、action,配置constant常量。 重点:Person的reducer和Count的Reducer要使用combineReducers进行合并, 合并后的总状态是一个对象!!! // 暴露store export default legacy_createStore( combineReducers({ count: countReducer, persons: personReducer }), applyMiddleware(thunk) );交给store的是总reducer,最后注意在组件中取出状态的时候,记得“取到位”。 export default connect( (state) => ({ personList: state.persons, count: state.count }), { addPerson: createAddPersonAction, } )(Person);优化:reducers文件夹中,编写index.js专门用于汇总并暴露所有的reducer 6. react-redux开发者工具的使用下载Chrome浏览器插件 地址:Redux-DevTools 浏览器调试工具 在项目中安装redux-devtools-extension npm i redux-devtools-extension 在store中进行配置 // 引入redux-devtools-extension import { composeWithDevTools } from "redux-devtools-extension"; // 暴露store export default legacy_createStore( combineReducers({ count: countReducer, persons: personReducer }), composeWithDevTools(applyMiddleware(thunk)) );成功配置如下 如果函数的调用参数相同, 则永远返回相同的结果. 它不依赖于程序执行期间函数外部任何状态或数据的变化, 只依赖于传入的参数 必须遵守以下一些约束 不得改写参数数据 不会产生任何副作用,例如网络请求,输入和输出设备 不能调用Date.now()或者Math.random()等不纯的方法 redux的reducer函数必须是一个纯函数 本文来自博客园,作者:你就是星光,转载请注明原文链接:https://www.cnblogs.com/xzqyl/p/17045385.html |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |