| createStroe - 创建一个store
| reducer - 用来改变state的值,结合了action的动作来分别处理
| action - 要执行的事件
| combineReducers - 将多个reducer合到一起,赋给createStroe
| replaceReducer - 替换reducer,改变state修改逻辑
| subscribe - 侦听Store的变化
| store.getState - 获取Store中的state值
| store.dispatch - 触发action,改变state的值
| provider - 将Store传递给内部组件
| connect - 将组件与redux的状态、事件关联起来
| applyMiddleware - 加载中间件
| bindActionCreators - 直接调用dispatch(action)()
| react-redux - react与redux结合
Redux
react是纯View层的框架,需要数据流进行支撑, 单一的状态树,主流数据流框架: Flux、Redux
UI -> action -> reducer -> store -> state -> UI
Redux是非异步的流程,如果需要使用异步操作使用 Redux-saga
一、Flux四部分
1、Dispatcher - 处理动作分发,维持Store之间的依赖关系
2、Store - 负责存储数据和处理数据相关逻辑
3、Action - 驱动Dispatcher的JS对象
4、View - 视图部分,负责显示用户界面
Dispatcher相当于Controller,Stroe相当于Modle,View相当于View,Action相当于用户的行为
二、Redux三个基本原则
1、唯一数据源 - 状态数据只存储在唯一的一个Store上
2、保持状态只读 - 不能直接修改Store的状态,需要派发一个action对象完成
3、数据改变只能通过纯函数完成
安装
Facebook官方提出了Flux思想管理数据流,同时也给出了自己的实现方案Flux来管理React应用
实现Flux思想的类库 Redux、Flux、reflux
$ npm i redux --save // 安装redux
$ npm i react-redux --save // redux与react结合
$ npm i react-router-redux --save // redux-router
$ npm i redux-devtools-extension --save // 安装可视化工具
引用:import { composeWithDevTools } from 'redux-devtools-extension'
在chrome中下载redux-devtools插件
https://github.com/zalmoxisus/redux-devtools-extension#usage
$ npm i redux-thunk --save
$ npm i redux-logger --save
引用redux: import { createStore } from 'redux'
一、Redux流程:
1、view直接触发dispatch
2、dispatch将action发送到reducer中后,根节点上会更新props,改变全局view
3、redux将view和store的绑定从手动编码中提取出来,放在了统一规范放在了自己的体系中
Action
action指令并不能直接改变state,action必须是json
let todoId = 0;
export const addTodo = (text) => {
return {
type: 'ADD_TODO', // 处理的类型(必要)
id: todoId++, // 存储数据当前的id标识
text // 传入的内容
}
}
通过 store.dispatch(action) 来派发到reducer中, 在reducer中改变state的值
Reducer
接收一个action值,纯方法不能定义ajax定义时间等,需要传入一个旧的状态在返回一个新的状态给action, 根据定义的action名对应处理state,并改变state值
let todo = (state, action) => {
// 这里通过action的type的值对应不同的事来处理
switch(action.type){
case 'ADD_TODO':
return {
state + 1;
}
break;
/* 上面只是单个add_todo, 这里要写成多个add_todo
case 'ADD_TODO':
return [
{
id: action.id,
text: action.text,
completed: false
},
...state
]
break;
*/
case 'SUB_TODO':
return {
state - 1;
}
break;
default: state;
}
}
1、combineReducers - 将多个的reducer合成一个
// 目录 reducer/index.js
import {combineReducers} from "redux";
import reducerA from "./reducerA";
import reducerB from "./reducerB";
export default combineReducers({
reducerA,
reducerB,
});
// createStore调用reducer
import reducers from './reducer/'
let store = createStore(reducers)
Store
Store是来保存数据的容器,只有一个Store,可以根据不同业务拆分成多个reducer, createStroe(reducer, 初始化的)
import { createStore } from 'redux';
import reducer from './reducers' // 获取定义的reducer
let stroe = createStroe(reducer); // 使用createStore(reducer, initialState初始化state, 中间件传入)来创建一个数据仓库
store.dispatch();
方法:
1、store.getState(): 获取State值
2、store.dispatch(action): 触发action,修改state的值
3、store.subscribe(listener),用来订阅状态的变化
添加一个变化的监听器,每当dispatch action的时候就会执行
// App组件
class App extends Component {
constructor(props){
super(props);
this.state = {
num: 0
}
}
componentDidMount() {
store.subscribe(this.handleChange.bind(this));
}
handleChange(){
this.setState({num: store.getState()})
}
addClick(){
store.dispatch({type: 'add'});
}
subClick(){
store.dispatch({type: 'sub'});
}
showState(){
debugger;
console.log(store.getState())
}
render() {
return (
<div className = "box" >
{this.state.num}
<input type="button" onClick={this.addClick} value="+" />
<input type="button" onClick={this.subClick} value="-" />
<input type="button" onClick={this.showState} value="查看state" />
</div>
)
}
}
State
state用于存储数据,state是只读的,改变需要触发action
state树就是一个对象,所有的reducer的都会加到state中,取state值,store.getState().
react-redux
$ npm i react-reudx --save // 安装
一、provider(store, children) - 将Store传到子组件中,一般用在入口文件
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from "react-redux";
import Store from "src/store";
import App from 'src/components/app';
import Chat from 'src/pages/Chat/Index';
// 1、使用Store让所有组件访问到
ReactDOM.render(
<Provider store={Store}>
<App>
<Chat />
</App>
</Provider>,
document.getElementById('app')
);
// 2、如果使用路由
ReactDOM.render(
<Provider store={store}>
<Router ref="router" history={hashHistory}>
<Route path='/' component={Index}>
<IndexRoute component={MainPage}></IndexRoute>
</Route>
</Router>
</Provider>
)
二、connect(mapStateToProps, mapDispatchToProps)(Component连接组件) - 连接react组件与redux store
1、mapStateToProps(state, ownProps) - 侦听Store的变化
state参数 - 如果Store中有变化此方法就会被调用,该回调函数返回一个纯对象,这个对象会与组件的props合并
ownProps参数 - 该参数的值为会飞经到组件的props,
2、mapDispatchToProps - 逻辑输出,相当于用store.dispatch(actionType) 来发出操作指令,来改变state值
Example:
// app.jsx
<Provider store={store}>
<Router ref="router" history={hashHistory}>
<Route path='/' component={Index}>
<IndexRoute component={MainPage}></IndexRoute>
</Route>
</Router>
</Provider>
// Index.jsx
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { bindActionCreators } from "redux";
import { connect } from "react-redux";
import actions from "src/actions";
class wechat extends Component {
constructor(props){
super(props);
this.state = {
}
}
componentDidMount(){
let { ACTIONS } = this.props;
ACTIONS.chat_init();
}
render(
// ...
)
}
let mapStateToProps=(state)=>{
let {sessions,user} = state.chatIndex;
return {
_sessions:sessions,
_user:user
};
};
let mapDispatchToProps=(dispatch)=>{
return {
ACTIONS: bindActionCreators(actions, dispatch)
};
};
export default connect(mapStateToProps,mapDispatchToProps)(wechat);
container组件
引用Redux将组件分两类container和component
container - 组件中使用redux获取数据,状态更新,从Redux获取state
bindActionCreators()
是通过dispatch将action包裹起来,这样可以通过bindActionCreators创建的方法,直接调用dispatch(action)(隐式调用)
import * as oldActionCreator from './action.js'
let newAction = bindActionCreators(oldActionCreator,dispatch)
调试工具
两种方法 1、下载redux-devtools包 2、chrome or Firfix 下载 Redux DevTools插件
1、使用Redux DevTools插件 代码中需要加配置
https://github.com/zalmoxisus/redux-devtools-extension
/* eslint-disable no-underscore-dangle */ // +
let store = createStore(
comput,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() // +
)
/* eslint-enable */ // +
2、redux-devtool 包的使用 https://github.com/gaearon/redux-devtools
项目目录
|- src
|-- reduxs // redux
|------ actions
|------ reducers
|-- router // 路由
|-- util // 工具
react-router-redux路由
redux管理的是应用状态(state),router管理的是路由,react-router-redux是保持路由与应用状态(state)同步
$ npm install --save react-router-redux // 安装
原理:允许使用react router库中的api,使用redux一样去管理应用状态state
https://www.jianshu.com/p/bccca5bb6338
http://blog.csdn.net/isaisai/article/details/78086913
https://segmentfault.com/a/1190000007862103
http://blog.csdn.net/sinat_17775997/article/details/69218382
| http://cn.redux.js.org/index.html // Redux中文文档
| http://www.liuyiqi.cn/2016/01/19/r2-counter/
| https://github.com/lewis617/react-redux-tutorial
| https://github.com/xgrommx/awesome-redux
| https://www.jianshu.com/p/bccca5bb6338 // react-router-redux 保持路由与应用状态(state)同步
| http://www.redux.org.cn/ // react-redux
| https://www.jianshu.com/p/1a2f3db4af61 // react-redux
| https://www.jianshu.com/p/9873d4ccb891 // connect 原理
| https://github.com/GuoYongfeng/redux-complete-sample
| https://github.com/gaearon/redux-devtools
| http://www.aliued.com/?p=3204
| http://blog.csdn.net/liwusen/article/details/54138854 // bindActionCreators
| http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
| https://github.com/allan2coder/React-SPA/blob/master/src/store/configureStore.dev.js // 示例 router3.0
国内查看评论需要代理~