Redux随笔
Redux简介
Redux是一个库,是JavaScript状态容器,提供可预测化的状态管理,他解决的组件间数据共享的问题。当然,在React中,要达到组件间数据共享的目的不一定非要用Redux,React提供了context api,在小型项目里面用context当然没什么问题,但是当页面复杂起来的时候,可能就需要统一并且易管理的Redux库了。
Redux三大原则
单一数据源
所有数据都存在唯一一棵树中
状态是只可读
简单的说,就是只有get方法,没有set方法,状态只能通过dispatch(action)更改
状态修改均由纯函数完成
1. 函数的返回结果只依赖于它的参数。 2. 函数执行过程里面没有副作用。
Redux核心
Redux学的时候可能觉得有点绕,但是学会了回头看,其实就三个东西
- action(对要分发(dispatch)的数据进行包装)
- reducers(识别发送的action的类型(type),返回一个新的状态(state)给store树更新)
- store(store 就是用来维持应用所有的 state 树 的一个对象。)
这是来自阮老师官网的图。它很好的解释了redux的工作原理,举例,当用户点击时(onClick),分发一个action (dispatch(action)),然后reducers就会被调用,reducers会被传入两个参数,一个当前的(旧的)state,一个是你dispatch的action,然后reducers根据action.type进行相应的数据处理,最后返回一个新的state给store树,store树更新后,React Components就会根据store进行重新渲染,就达到了状态更新的效果了。
React中的目录
├── src/ ├── action// 存放action ├── components // 存放展示组件(组件的渲染,它不依赖store,即与redux无关) ├── contrainers// 存放容器组件 (在这里作了数据更新的定义,与redux相关) ├── reducers // 存放reducers ...
Action
action是对要分发的数据进行包装的,当我们要改变store树时,只需要分发对应的action dispatch(add()),然后经过reducers处理返回一个新的state,store树就得到了更新。
以计数器为例,就应该有两个action,一个加一,一个减一。return的内容可以不只有type,还可以有自己自定义的数据(参照如下),但是必定要有type,因为reducers是根据action.type进行识别处理数据的。
// src/action/index.js export const add = () => { return { type: "ADD" }; }; export const less = () => { return { type: "LESS" }; }; // let id = 0; // export const getWeatherSuccess = payload => { // return { // type:"SUCCESS", // payload, // id:id++ // }; // };
Reducers
Reducers的写法基本都是固定的,形式如下,state初始值根据需求自定,唯一要注意的时,我们不可以更改state,只能返回一个新的state,因为Reducers是一个纯函数。
为什么Reducers一定要是纯函数,其实Redux只通过比较新旧两个对象的存储位置来比较新旧两个对象是否相同(也就是Javascript对象浅比较)。如果在reducer内部直接修改旧的state对象的属性值,那么新的state和旧的state将都指向同一个对象。因此Redux认为没有任何改变,返回的state将为旧的state。
Reducers这么设计的目的其实是出于性能的考虑,如果Reducers设计成直接修改原state,则每次修改都要进行遍历对比,即JavaScript深比较,对性能消耗大很多,所以设计成纯函数的形式,每次仅需要一次浅对比即可。
好吧,上面巴拉巴拉那么多,其实暂时不看也不影响,下面继续举Count的reducerrs例子
// src/reducers/count const count = (state = 0,action) => { switch (action.type) { case 'ADD': return state+1 case 'LESS': return state-1 default: return state } } export default count;
这里只是一个Count的Reducer,在实际情况中,肯定不止一个Reducer,每个state也不是单单是一个数值,state一般都是对象的形式,然后再在state对象里面存该类的值,并且也不可能都写在一个js文件中,那么就需要用到combineReducers进行Reducer的合并。
// src/reducers/index import {combineReducers} from 'redux' import count from './count' //假设有个weather的reducer import weather from './weather' const reducers = combineReducers({ count, weather }) export default reducers;
Store
Store提供了三个API:
- 提供 getState() 方法获取 state;
- 提供 dispatch(action) 方法更新 state;
- 通过 subscribe(listener) 注册监听器,注销监听器;
store一般都是在顶层组件创建,然后通过react-redux提供的Provider对子组件进行连接
// src/components/App import React, { Component } from 'react'; import {Provider} from 'react-redux' import { createStore } from 'redux'; import reducers from '../reducers' import Count from '../contrainers/Count' let store = createStore(reducers) class App extends Component { render() { return ( <Provider store={store}> <CountAndWeather/> </Provider> ); } } export default App;
react-redux
react-redux是一个官方提供的redux连接库,它提供了一个组件<Provider></Provider>和一个API connect(),<Provider>接受一个store作为props,而connect提供了在整个React应用的任意组件中获取store中数据的功能。即在<Provider>包裹的子组件里面,我们可以通过connect()获取store。
connect是一个高阶函数,第一个括号的两个参数,第一个是对state的映射,第二个是dispatch的映射,第二个括号的参数是需要连接Redux的组件。