Flux 是一种架构思想,专门解决软件的结构问题。它跟MVC架构是同一类东西,但是
更加简单和清晰。Flux存在多种实现(至少15种)
https://github.com/voronianski/flux-comparison
redux是flux的一种实现
Redux最主要是用作应用状态的管理。简言之,Redux用一个单独的常量状态树
(state对象)保存这一整个应用的状态,这个对象不能直接被改变。当一些数据变化了,
一个新的对象就会被创建(使用actions和reducers),这样就可以进行数据追踪,实现时
光旅行。
管理状态,非父子通信
状态快照,数据缓存,减少服务器压力,提高用户体验
下载
cnpm intsall --save redux
主要利用发布者订阅者模式
创建store对象
import {
createStore} from 'redux' //create方法创建一个store对象
//接收两个参数一个是老对象的状态,一个是发布者传过来的对象
//必须满足纯函数的写法 深复制老状态一份在改变新状态返回新状态
const reducer = (prevState={
isCollapsed:false
},action) =>{
var newstate = {
...prevState} //深复制老状态一份
newstate.isCollapsed = action.payload
return newstate
//console.log(action);
}
const store = createStore(reducer)
export default store
发布者传东西的那个组件
import store from '../../redux/store';
store.dispatch({
type:"MySideMenuCollapsed",
payload:isCollapsed
})
一旦dispatch触发就会把当前对象传给store,store借助reducer修改
订阅者 (接收东西的那个组件)
import store from '../../redux/store'
componentDidMount() {
store.subscribe(()=>{
// console.log("接收到的值",store.getState())
this.setState({
collapsed:store.getState().isCollapsed
})
})
}
需要注意在发布的时候type属性必须传,因为如果有许多组件要同时修改同一个状态的话这个时候会混淆 传了type时候可以作出判断
middleware中间件 解决异步处理
cnpm install --save redux-thunk redux-promise
可以让action返回一个函数 它会会传过来一个dispatch形参 自己决定什么时候发送action
actionCreate = ()=>{
return (dispatch)=>{
axios.get("http://localhost:8000/roles").then(res => {
// console.log(res.data)
//自己决定什么时候发送
dispatch({
type:"SetRoleList",
payload:res.data
})
})
}
import {
createStore,applyMiddleware} from 'redux' //create方法创建一个store对象
import reduxThunk from 'redux-thunk'
const reducer = (prevState={
isCollapsed:false, //管理侧边栏的隐藏和显示
roleList:[] //缓存role里面的列表
},action) =>{
let {
type,payload} = action
switch(type){
case "MySideMenuCollapsed":
var newstate = {
...prevState} //深复制老状态一份
newstate.isCollapsed = action.payload
return newstate
case "SetRoleList":
var newstate = {
...prevState}
newstate.roleList = payload
return newstate
default:
return prevState
}
//console.log(action);
}
const store = createStore(reducer,applyMiddleware(reduxThunk))
//创建store,顺便应用中间件thunk,如果action是函数我来处理
export default store
一旦store中的roleList发生变化那么store.subscribe(()=>{})就会触发所以为了避免第一开始没有值也需要订阅一次
this.unscribe = store.subscribe(()=>{
// console.log("请求结束",store.getState().roleList);
this.setState({
datalist:store.getState().roleList
})
})
同时在销毁的过程中要解除订阅
componentWillUnmount(){
this.unscribe() //取消订阅
}
import reduxPromise from 'redux-promise'
const store = createStore(reducer,applyMiddleware(reduxThunk,reduxPromise))
//创建store,顺便应用中间件thunk,如果action是函数我来处理
// 创建store,顺便应用中间件redux-promise,如果action 是promise,我来处理
dispatch 出去的action对象可以是promise对象则
actioncreate = ()=>{
return axios.get("http://localhost:8000/rights").then(res=>{
return {
type:"SetRightList",
payload:res.data
}
})
}
在你dispatch的时候.then可以访问到发送完成之后的promise状态
componentDidMount() {
// axios.get("http://localhost:8000/rights").then(res=>{
// // console.log(res.data);
// this.setState({
// datalist:res.data
// })
// })
if(store.getState().rightList.length===0){
store.dispatch(this.actioncreate()).then(data=>{
// console.log(data);
this.setState({
datalist:data.payload
})
})
}else{
console.log("使用缓存")
this.setState({
datalist:store.getState().rightList
})
}
}
只能有一个syore
store只能接受一个reducer
把reducer拆开一个个的,每个reducer一个文件 combineReducer合并所有的reducer
const collapsedReducer = (prevState=false,action)=>{
// console.log(action)
// “修改状态”
let {
type,payload} = action
switch(type){
case "MySideMenuCollapsed":
return payload
default:
return prevState
}
}// 只要状态已返回, 自动同步了
export default collapsedReducer
const rightListReducer = (prevState=[],action)=>{
// console.log(action)
// “修改状态”
let {
type,payload} = action
switch(type){
case "SetRightList":
var newstate = [...prevState,...payload]
return newstate
default:
return prevState
}
}// 只要状态已返回, 自动同步了
export default rightListReducer
利用combineReducers合并reducers
import {
createStore,applyMiddleware,combineReducers} from 'redux' //createStore 方法创建一个store对象
import reduxThunk from 'redux-thunk'
import reduxPromsie from 'redux-promise'
import roleListReducer from './reducers/roleListReducer'
import rightListReducer from './reducers/rightListReducer'
import collapsedReducer from './reducers/collapsedReducer'
//创建一个reducer,“修改状态” (接收老状态,修改的值, 深复制之后, 再返回一个新的状态)
//合并子 reducer
const reducer = combineReducers({
isCollapsed:collapsedReducer,
roleList:roleListReducer,
rightList:rightListReducer
})
/*
reducer保证是纯函数 --函数式
//1. 对外界没有副作用的函数
//2. 同样的输入,得到同样的输出
不是纯函数
//var myname ="kerwin"
// function test(){
// myname="xiaoming"
// }
// test()
//纯函数
// var myname ="kerwin"
// function test(myname){
// myname="xiaoming"
// }
// test(myname)
//不纯
var obj = {myname:"kerwin"}
function test(obj){
obj.myname = "xiaoming"
}
test(obj)
//纯
var obj = {myname:"kerwin"}
function test(obj){
var newobj = {...obj}
newobj.myname = "xiaoming"
}
test(obj)
*/
// store,只能接受一个reducer
// app开发 只能有一个store
// 轮船运火车 (reducer拆开一个个, 每个reducer一个文件, combineReducce(合并所有reducer))
const store = createStore(reducer,applyMiddleware(reduxThunk,reduxPromsie))
// 默认 action 只能是普通对象 {type:""}
// 创建store,顺便应用中间件thunk,如果action 是函数,我来处理
// 创建store,顺便应用中间件redux-promise,如果action 是promise,我来处理
export default store
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducer,composeEnhancers(applyMiddleware(reduxThunk,reduxPromsie)))
需要有一个高阶组件connect包裹发布者和订阅者
这样就不需要子组件发布和订阅了全部交给高阶组件
但是由于高阶组件无法直接获得store所以最外层需要一个provider来传给它
首先在项目最外层用provider组件把他包裹起来把store传进去
import store from ‘./redux/store’
class App extends Component{
render(){
return (
<Provider store={
store}>
<BlogRouter/>
</Provider>
)
}
}
import React, {
Component } from 'react';
import './App.css';
import BlogRouter from './router'
// import { NavLink } from 'react-router-dom'
import {
Provider} from 'react-redux'
import store from './redux/store'
class App extends Component{
render(){
return (
<Provider store={
store}>
<BlogRouter/>
</Provider>
)
}
}
/*
context 跨层级的通信
*/
export default App;
然后再根据高阶组件包裹
export default connect(mapStateToProps,mapDispatchToProps)(Right)
第一个参数 mapStateToProps 获得store里面的属性的这样被包裹的子组件就有了你返回的这个属性了
const mapStateToProps=(state)=>{
return {
datalist:state.rightList
}
}
```
第二个参数是用来dispatch的
```
const mapDispatchToProps = {
setList:()=>{
//返回一个promsie对象
return axios.get("http://localhost:8000/rights").then(res=>{
return {
type:"SetRightList",
payload:res.data
}
})
}
}
一旦监测到状态长度为0则发起axios请求
componentDidMount(){
if(this.props.datalist.length===0){
//
this.props.setList()
}