Redux
- Redux是一个数据管理框架,经常和React搭配使用
- 由于React写大型复杂应用易遇到困难(代码结构、组件间通信问题),2014年Facebook提出Flux架构概念。
- 2015年,Redux出现,将Flux与函数式编程结合在一起
- 最大优势:自带规范,将数据管理定于为三个核心概念
- store // 数据仓库 一个数据就是一个房间
- reducer // 组合仓库里面各个房间的工具
- action // 给房间发放指令过程,接收action发送过来的指令,然后更新房间数据
安装
npm install redux
一般在react使用redux的话要安装react附加包
npm install react-redux
npm install --save-dev redux-devtools // 开发者工具可以不装
store
Store 就是把它们联系到一起的对象。Store 有以下职责:
- 维持应用的 state;
- 提供 getState() 方法获取 state;
- 提供 dispatch(action) 方法更新 state;
- 通过 subscribe(listener) 注册监听器;
- 通过 subscribe(listener) 返回的函数注销监听器。
再次强调一下 Redux 应用只有一个单一的 store。当需要拆分数据处理逻辑时,你应该使用 reducer 组合 而不是创建多个 store。
reducer
Reducers 指定了应用状态的变化如何响应 actions 并发送到 store 的,记住 actions 只是描述了有事情发生了这一事实,并没有描述应用如何更新 state。
action
Action 是把数据从应用(译者注:这里之所以不叫 view 是因为这些数据有可能是服务器响应,用户输入或其它非 view 的数据 )传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。

以下为redux的一个简单实现
目录为:
├── actions // actions 目录
| ├── friend.js // 单个action文件
├── reducers // reducers 目录
| ├── friend.js // 单个reducer文件
| ├── index.js // redux reducer文件 在这里处理所有reducer文件,把单个reducer合并然后export
├── store // store目录
| ├── index.js // redux store文件
├── views // 组件视图目录
| ├── friend
| ├── index.js // friend组件文件
├── App.js // App组件文件
├── index.js // 项目入口文件
文件明细
在项目入口文件 index.js要引入store 并且定义全局的store
import React from "react";
import { render } from "react-dom";
import { Provider } from "react-redux"; // 引入Provider组件
import { store } from "./store";
import App from "./App";
render(
<Provider store={store}> // 传入store
<App></App>
</Provider>,
document.getElementById("root")
);
在store/index.js文件下定义store
import { applyMiddleware, compose, createStore } from "redux";
import rootReducer from "../reducers"; // 引入合并后reducer对象
const middlewares = [];
// 开发环境使用redux报错信息,可不用
if (process.env.NODE_ENV === "development") {
const { logger } = require("redux-logger");
middlewares.push(logger);
}
export const store = compose(applyMiddleware(...middlewares))(createStore)(rootReducer);
// 通过redux里的方法构造store
因为在store/index.js引入了reducers,接下来我们看一下reducers目录下的文件内容
reducers/index.js:
import { combineReducers } from "redux";//引入combineReducers方法,将所有单个reducer合并
import friend from "./friend"; //引入friend reducer文件
export default combineReducers({
friend
});
reducers/friend.js:
import { ADD_LIST, DEL_ITEM } from '../actions/friend'//引入action文件,获取到action里面定义的动作
const initialState = {
list: [
{ name: 'lizi', id: 0 },
{ name: 'vue', id: 1 },
{ name: 'react', id: 2 }
]
} // 定义初始化的 state数据
// 向外抛出一个方法函数
export default (state = initialState, action = {}) => {
const { type, data } = action
let List = state.list
switch (type) { // 监听dispatch触发的type,并执行相对于的方法,进行对state数据的操作,然后返回修改后的state,更新到对应的组件。
case ADD_LIST:
List.push(data)
return Object.assign({}, state, { list: [...List] }) // 这边List要解构,不然和state.list的内存地址是一样的,js认为数据没改变
case DEL_ITEM:
List = List.filter(item => item.id != data)
return Object.assign({}, state, { list: [...List] })
default:
return state
}
}
接下来我们看一下actions/friend.js里面做了什么东西。
import { store } from "../store";// 引入store对象
export const ADD_LIST = "ADD_LIST"; // 定义导出方法名
export const DEL_ITEM = "DEL_ITEM";// 定义导出方法名
export function addList(data) { //定义导出对应的方法,提供在组件内调用
const dispatch = store.dispatch;// 获取到store.dispatch
setTimeout(() => {
dispatch({ type: ADD_LIST, data }); // 触发reducer里面的对应方法
}, 1000);// 异步更新
// dispatch({ type: ADD_LIST, data }); // 同步更新
}
export function delItem(data) {
const dispatch = store.dispatch;
dispatch({ type: DEL_ITEM, data });
}
我们回到App.js组件内,App.js只是简单的引入views/friend.js文件
import React from 'react'
import Friend from './views/friend'
export default class App extends React.Component {
render() {
return (
<div>
<Friend></Friend>// 这边并没有给Friend组件注入props,我们看一下如何在friend组件使用全局的state
</div>
)
}
}
最后,我们看一下views/friend.js文件,看看如何在组件内使用全局state的值,并且调用已经定义的修改方法
import React from 'react'
import { connect } from 'react-redux' // 在react-redux模块内引入connect方法
import { addList, delItem } from '../../actions/friend'// 引入对应的action方法
class friend extends React.Component {
constructor(props) {
super(props)
this.state = {
value: ''
}
}
render() {
const {
value
} = this.state
const {
friendList
} = this.props // 通过connect获取到state.friend.list
return (
<div>
{friendList.map((item, index) =>
<div key={item.id}>
<p>{item.name}</p>
<button onClick={() => {
delItem(item.id)
}}>del</button>
// button方法触发action里面的delItem方法,修改数据
</div>
)}
<input value={value} onChange={e => {
this.setState({ value: e.target.value })
}} />
<button onClick={(e) => {
addList({ name: value, id: friendList.length })
this.setState({ value: '' })
}}>add</button>
// button方法触发action里面的addList方法,修改数据
</div>
)
}
}
export default connect((state) => {
return {
friendList: state.friend.list
}
})(friend) // 通过connect方法,获取到state的值,并且赋值到组件的props.friendList
以上为redux的一个简单实现过程,如果需要添加多个reducer,则需要在reducers目录下新建对应的reducer,并且在reducers/index.js中进行合并,即可在页面上使用