redux
Redux是一个
数据状态管理
插件,当使用React或是vue开发组件化的SPA程序时,组件之间共享信息是一个非常大的问题。例如,用户登陆之后客户端会存储用户信息(ID,头像等),而系统的很多组件都会用到这些信息,当使用这些信息的时候,每次都重新获取一遍,这样会非常的麻烦,因此每个系统都需要一个管理多组件使用的公共信息的功能,这就是redux的作用。
简单使用
import { createStore } from 'redux'
- 第一步:定义计算规则,即reducer
function counter(state = 0, action) { switch (action.type) { case 'INCREMENT': return state + 1 case 'DECREMENT': return state - 1 default: return state }}
- 第二步:根据计算规则生成store
let store = creatStore(counter);
- 第三步:定义数据(state)变化之后的派发规则
store.subscribe(() => { console.log('fn1 -> current state', store.getState())})store.subscribe(() => { console.log('fn2 -> current state', store.getState())})
- 第四步:触发数据变化
store.dispatch({ type: 'INCREMENT',})
在React中使用
redux经常和react搭配使用,使用React开发系统,绝大部分都需要结合Redux来使用,下面介绍一下如何在React中使用redux.
前四步和之前的差不多,但是要注意结构的拆分。
导入依赖
npm install redux --savenpm install react-redux --save
文件目录结构
reducers
index.js
Reducer 函数负责生成 State。由于整个应用只有一个 State 对象,包含所有数据,对于大型应用来说,这个 State 必然十分庞大,导致 Reducer 函数也十分庞大。若把传入Reducer的Action改变为State的属性,属性间没有关联,我们就可以把Reducer函数拆分,不同函数负责处理不同属性,最终用
combineReducers
合并成一个大的Reducer即可。import { combineReducers } from 'redux';import userInfo from './userInfo'const rootRuducer = combineReducers({ userInfo, //userInfo是State的一个属性,也是一个action方法,同名。若不想同名,可写成a: doSomethingWithA的形式(a是State的属性)。})export default rootRuducer;
userInfo.js
import * as actionTypes from '../constants/userInfo';const initState = {}export default function userInfo (state = initState, action) { switch(action.type) { case actionTypes.UPDATE_CITYNAME: return action.data default: return state }}
actions
userInfo.js
import * as actionTypes from '../constants/userInfo';export function updateCityName(data) { return { type: actionTypes.UPDATE_CITYNAME, data, }}export function XXX(){ return {}}
constants
userInfo.js
被多个地方引用,这样可以方便修改
export const UPDATE_CITYNAME = 'UPDATE_CITYNAME';
store
configureStore.js
导出创建store的函数
import { createStore } from 'redux';import rootRuducer from '../reducers';export default function configureStore(initState) { const store = createStore(rootRuducer, initState, window.devToolsExtension ? window.devToolsExtension() : undefined ); return store;}
containers
存放页面的文件夹
index.js
mapStateToProps
会订阅 Store,每当state
更新的时候,就会自动执行,重新计算 UI 组件的参数,从而触发 UI 组件的重新渲染。mapStateToProps
的第一个参数总是state
对象,还可以使用第二个参数,代表容器组件的props
对象。mapDispatchToProps
是connect
函数的第二个参数,用来建立 UI 组件的参数到store.dispatch
方法的映射。也就是说,它定义了哪些用户的操作应该当作 Action,传给 Store。它可以是一个函数,也可以是一个对象。如果
mapDispatchToProps
是一个函数,会得到dispatch
和ownProps
(容器组件的props
对象)两个参数,返回一个对象,该对象的每个键值对都是一个映射,定义了 UI 组件的参数怎样发出 Action。bindActionCreators(actionCreators, dispatch)
把一个 value 为不同 的对象,转成拥有同名 key 的对象。同时使用 对每个 action creator 进行包装,以便可以直接调用它们。一般情况下你可以直接在 实例上调用 。如果你在 React 中使用 Redux, 会提供 函数让你直接调用它 。
惟一会使用到
bindActionCreators
的场景是当你需要把 action creator 往下传到一个组件上,却不想让这个组件觉察到 Redux 的存在,而且不希望把 或 Redux store 传给它。import React from 'react';import { bindActionCreators } from 'redux';import { connect } from 'react-redux';import * as userInfoActionsFromOtherFile from '../actions/userInfo.js';class App extends React.Component { constructor(props) { super(props); this.state = { initDone: false } } componentDidMount() { this.setState({ initDone: true, }) } render() { return (
{this.state.initDone ? this.props.children : 'loadding...'}) }}function mapStateToProps(state) { return { userInfo: state.userinfo, }}function mapDispatchToProps(dispatch) { return { userInfoAction: bindActionCreators(userInfoActionsFromOtherFile, dispatch), }}export default connect( mapStateToProps, mapDispatchToProps // 定义了哪些用户的操作应该当作 Action,传给 Store)(App);
index.js
React-Redux 提供
Provider
组件,可以让容器组件拿到state
。所以在入口文件夹中,先创建store,然后再把包裹一层。import React from 'react';import ReactDOM from 'react-dom';// import { render } from 'react-dom';import { Provider } from 'react-redux';import configureStore from './store/configureStore';import App from './containers//index';const store = configureStore();ReactDOM.render(