为什么需要redux
javaScript开发的应用程序,已经变得非常的复杂了,需要管理的状态越来越多,包括:服务器返回的数据,缓存数据,用户操作产生的数据等等, 这些状态可能被多个组件共享使用,一个状态的改变可能以前多个对象的联动变化,Redux就是一个帮助我们管理state的容器。 就是让不同组件间可以轻松的共享该数据,同时Redux通过强制单向数据流,使得应用程序的状态可预测和可控
简单的说:redux是js的状态(数据)管理器,让组件直接可轻松共享状态(数据)。
redux 设计理念
举个例子: 比如我有一个friends列表数据需要管理:
const initialState = {
friends: [
{ name:"xiaoming", age:18 },
{ name:"xiaohong", age:22 },
{ name:"xiaozhang", age:44 }
]
}
页面A通过products.push的方式增加一条数据,页面B通过products[0].age = 20修改一条数据。这样没有统一的规范来操作这些数据,那整个数据的变化是无法追踪的。
Redux中是如何做的 ?
◆ store:
因为多个页面都需要用到friends数据,所以我们要将friends数据存入store中
◆ action:
变更数据,必须通过dispatch(派发) action 来更新
action就是一个普通的js对象,描述了这次更新的 type 和 action
下面就是几个action:
const action1 = { type: "ADD_FRIEND", info: {name:"lucy", age: 20}}
const action2 = { type: "INC_AGE", index: 0 }
const action3 = { type: CHANGE_NAME, playload: { index: 0, newName:"jay"}}
强制使用action的好处是: 数据变更都是根据action对象来做变化的,所以可清晰知道数据到底发生了什么变化,并且变化是可追踪,可预测的
◆ reducer:
我们已知Redux是通过派发action来做数据变更的,也就是说通过action中的type和content来修改state(数据),但action仅仅是个js对象(保存着要修改的数据),怎么让新数据修改掉旧state(数据)呢?
通过纯函数reducer来修改state(数据)。reducer会将传入的 state(旧) 和 action 结合起立生成一个 新的state
下面就是一个reducer函数的写法:
function reducer(state = initialState, action) {
switch (action.type){
case "ADD_FRIEND":
return {...state, friends:[...state.friends, action.info]}
case "INC_AGE":
return {xxxxxxxxx}
default:
return state;
}
}
Redux简单使用:
这里先使用一个简单的,非React脚手架项目演示一下。
步骤:
首先,创建一个文件夹(LearnRedux), 在该文件夹下创建一个src文件夹,src文件夹下再创建一个store文件夹。
接着,执行 npm init -y 创建一个 package.json文件
◆ 安装redux库:
npm install redux 或 yarn add redux
◆ 在store目录下创建一个index.js:
第1行: 导入redux中的 createStore
第4行: 是要保存在store中的数据,真实开发中一般来自于网络请求
第15行: 定义一个reducer函数,用来将 action 和 保存在store中的数据 产生联系(即:更改store中存储的数据)。 reducer是一个纯函数,这个函数在后面创建store的时候会被作为参数传入,传入后会被redux自动调用,并且会传递 state 和 action 给reducer函数。
第26行: 通过导入的 createStore函数创建一个store,入参就是定义的 reducer函数
第28行: 导出供其他使用
◆ 在某个页面中获取存储在store中的数据:
第1行: 导入我们创建的 store
第4行: 通过store的 getState() 方法获取存在在store中的共享数据
◆ 在某个页面中修改存储在store中的数据:
第1行: 导入我们创建的 store
第4行: 创建一个 action对象
第7行: 通过store的 dispatch() 方法派发action,对共享值进行修改。(派发的action对象会传递给reducer函数,reducer函数会被重新执行)
◆ 在某个页面中订阅存储在store中的数据:
当修改了store中的值,就会自动执行该回调函数
第1行: 导入我们创建的 store
第5行: 通过store的 subscribe() 函数, 对store中的数据进行订阅。函数入参是一个 回调函数 。这样一旦调用dispatch去修改store中的值,就会自动执行该回调函数
第15行:subscribe函数会返回一个新的函数,当调用这个新函数可以取消订阅,这样后面再对store中的值进行修改时,就不会执行第5行传入的那个 回调函数 了
通过控制台打印,我们可以发现修改成 "小李" 时,订阅回调函数没有执行,因为在修改成 小李 之前取消了订阅。
还发现第11行 和 12行 都是修改 name="小红", 订阅回调函数依旧会执行,也就是只要修改了store中的值,不管两次值是不是一样,都会调用订阅回调函数。