1- redux基础
1-1 action creators
统一管理所有的action对象
// 创建数据仓库 import {createStore} from 'redux' let initState = { name:'小白', age:99 } // 第一个形参: 上一次的状态 // 第二个形参: 定义的规则 {type:'changeName',name:'小黑'},{type:'changeAge',age:100} function reducer(state=initState,action){ switch(action.type){ case 'changeoneName': return { ...state, name:action.name } case 'changeAge': return { ...state, age:action.age } default: return { ...state } } } export const actions = { changeName:(name)=>({type:'changeoneName',name:name}), changeAge:(age)=>({type:'changeAge',age}) } let store = new createStore(reducer) export default store
---one.jsx
import {actions} from '../store' change(){ // 修改数据仓库的name // store.dispatch({type:'changeName',name:'小黑'}) store.dispatch(actions.changeName('小蓝')) // this.setState({}) console.log(store.getState()); }
1-2 action types
统一管理所有的type
const TYPES = { CHANGE_NAME:'CHANGE_NAME', CHANGE_AGE:'CHANGE_AGE' } // 第一个形参: 上一次的状态 // 第二个形参: 定义的规则 {type:'changeName',name:'小黑'},{type:'changeAge',age:100} function reducer(state=initState,action){ switch(action.type){ case TYPES.CHANGE_NAME: return { ...state, name:action.name } case TYPES.CHANGE_AGE: return { ...state, age:action.age } default: return { ...state } } } export const actions = { changeName:(name)=>({type:TYPES.CHANGE_NAME,name:name}), changeAge:(age)=>({type:TYPES.CHANGE_AGE,age}) } let store = new createStore(reducer) export default store
1-3 reducer拆分
根据功能拆分模块
---one.js
// one模块 let initState={ name:'小one', age:'10' } const TYPES = { CHANGE_ONE_NAME:'CHANGE_ONE_NAME', CHANGE_ONE_AGE:'CHANGE_ONE_AGE' } function reducer(state=initState,action){ switch(action.type){ case TYPES.CHANGE_ONE_NAME: return { ...state, name:action.name } case TYPES.CHANGE_ONE_AGE: return { ...state, age:action.age } default: return { ...state } } } export const actions = { changeNameAction:name=>({type:TYPES.CHANGE_ONE_NAME,name}), changeAgeActions:age=>({type:TYPES.CHANGE_ONE_AGE,age}) } export default reducer
---two.js
// one模块 let initState={ name:'小two', age:'20' } const TYPES = { CHANGE_TWO_NAME:'CHANGE_TWO_NAME', CHANGE_TWO_AGE:'CHANGE_TWo_AGE' } function reducer(state=initState,action){ switch(action.type){ case TYPES.CHANGE_TWO_NAME: return { ...state, name:action.name } case TYPES.CHANGE_TWO_AGE: return { ...state, age:action.age } default: return { ...state } } } export const actions = { changeNameAction:name=>({type:TYPES.CHANGE_TWO_NAME,name}), changeAgeActions:age=>({type:TYPES.CHANGE_TWO_AGE,age}) } export default reducer
---index.js
整合到一起
// 创建数据仓库 import {createStore,combineReducers} from 'redux' import one from './modules/one' import two from './modules/two' // 第一个形参: 上一次的状态 // 第二个形参: 定义的规则 {type:'changeName',name:'小黑'},{type:'changeAge',age:100} // 将不同不模块的reducer整合为一个 let rootReducer = combineReducers({ one:one, two }) let store = new createStore(rootReducer) export default store
组件中使用 --- one.jsx
import React, { Component } from 'react' import store from '../store' // 取别名 import {actions as actionsone} from '../store/modules/one' import {actions as actionstwo} from '../store/modules/two' export default class One extends Component { componentDidMount(){ this.uns= store.subscribe(()=>{ // 开启监听,每次dispatch都会触发 this.setState({}) }) } componentWillUnmount(){ // 取消监听 this.uns() } change(){ // 修改数据仓库的name // store.dispatch({type:'changeName',name:'小黑'}) // store.dispatch(actionsone.changeNameAction('小蓝')) // 修改two的name store.dispatch(actionstwo.changeNameAction('小绿')) // this.setState({}) console.log(store.getState()); } change1(){ // 修改数据仓库的age // store.dispatch({type:'changeAge',age:100}) // this.setState({}) console.log(store.getState()); } render() { console.log(store.getState()); // 分模块获取状态 let {one,two} = store.getState() return ( <div className='box'> <h1>one组件</h1> <h2>数据仓库的 name---{one.name}---{two.name}</h2> <h2>数据仓库的 age---{one.age}</h2> <button onClick={()=>this.change()}>修改name</button> <button onClick={()=>this.change1()}>修改age</button> </div> ) } }
1-4 redux-devtools工具
1- 谷歌使用
码云--->搜索redux-devtools--> for chrome---点击 last -->下载--> 添加到扩展程序
创建数据仓库时添加
let store = new createStore(rootReducer,window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__())
2- 火狐
设置---》 面向开发者扩展---> 搜索redux-devtools--->安装
2- react-redux
2-1 安装
npm i react-redux --save
2-2 使用
react-redux将组件的与数据仓库相关逻辑代码和组件视图结构分开
-
容器型组件
-
负责处理逻辑
-
与数据仓库关联
-
状态就是数据仓库
-
-
UI型(视图)组件
-
主要用来显示数据
-
与数据仓库的状态没有关联
-
状态从props获取
-
2-2-1 provider
provider: 发送store
import {Provider} from 'react-redux' import store from './store' ReactDOM.render( // 发送数据仓库 <Provider store={store}> <App /> </Provider> , document.getElementById('root') );
2-2-2 connect
connect连接展示组件和容器组件
-
mapStateToProps: 输入逻辑,获取store的状态,返回一个对象,将数据对象传到到展示型组件中
-
mapActionsToProps: 输出逻辑,定义触发action对象来修改store的状态的方法。也要返回一个对象,将方法传到展示组件中
-
展示组件通过props接收传递的数据
import React, { Component } from 'react' import {connect} from 'react-redux' import store from '../store' // 取别名 import {actions as actionsone} from '../store/modules/one' import {actions as actionstwo} from '../store/modules/two' class One extends Component { change(){ this.props.changeName() } change1(){ this.props.changeAge(999) } render() { console.log(this.props); let {name,twoname,age} = this.props return ( <div className='box'> <h1>one组件</h1> <h2>数据仓库的 name---{name}---{twoname}</h2> <h2>数据仓库的 age---{age}</h2> <button onClick={()=>this.change()}>修改name</button> <button onClick={()=>this.change1()}>修改age</button> </div> ) } } // connect() 第一个形参 // 输入逻辑, 将数据仓库状态输入到组件中. // 有一个默认形参,就是数据仓库的状态 let mapStateToProps = state=>{ console.log(state,'111111'); // 必须有返回值,就是向展示型组件(One组件)传递的数据 return { name:state.one.name, twoname:state.two.name, age:state.one.age } } // 第二个形参:输出逻辑, 改变数据仓库的状态的操作 // 类似于vuex中mapActions方法。 let mapActionsToProps = dispatch=>{ return { // changeName:()=>dispatch({type:'CHANGE_ONE_NAME',name:'小红'}) changeName:()=>dispatch(actionsone.changeNameAction('小红')), changeAge:(age)=>dispatch(actionsone.changeAgeActions(age)) } } export default connect(mapStateToProps,mapActionsToProps)(One)
3-redux高阶
3-1 bindActionCreators
帮助我们做dispatch的操作
import {bindActionCreators} from 'redux' // 第二个形参:输出逻辑, 改变数据仓库的状态的操作 // 类似于vuex中mapActions方法。 let mapActionsToProps = dispatch=>{ return { // changeName:()=>dispatch({type:'CHANGE_ONE_NAME',name:'小红'}) // 将actionsone中的action依次定义 // changeName:()=>dispatch(actionsone.changeNameAction('小红')), // changeAge:(age)=>dispatch(actionsone.changeAgeActions(age)) // 将actionsone 的action对象同意触发 fn:bindActionCreators(actionsone,dispatch) } }
3-2 selectors
类似于计算属性,由state派发出的新得数据
---two.js
export let getTwoName = function(state){ return state.two.name } export let getTwoAge = state=>state.two.ages export let ageFor = state=>state.two.ages+'岁' export let total = state=>state.two.list.length
---Two.jsx
// 输入逻辑 //数据的传递 let mapStateToProps = state=>{ return { name:getTwoName(state), age:getTwoAge(state), agefor:ageFor(state), list:state.two.list, total:total(state) } }
3-3 reselect
1- 安装
npm i reselect --save
2- 使用
定义selectors只有依赖的数据改变时才重新计算。
// 计算平均 // export let getAver = state=>{ // console.log('计算平均数'); // let sum = 0 // state.one.list.forEach(item=>{ // sum+=item.num // }) // return sum/state.one.people // } // 通过reselect改写 // 第一个参数,所依赖的selectors // 只有list和people改变时才重新计算 export let getAver = createSelector([getList,getPeo],(list,peo)=>{ console.log('计算平均数'); let sum = 0 list.forEach(item=>{ sum+=item.num }) return sum/peo })
3-4 redux middleware 中间件
1-自定义中间件
1- 打印
// 定义一个打印的中间件 logger // let myLogger = function(store){ // return function(next){ // return function(action){ // // // console.log('本次触发的action',action); // console.log('改变之前的状态',store.getState()); // next(action) // console.log('最新的状态',store.getState()); // console.log('=================================='); // } // } // } let myLogger =store=>next=>action=>{ // console.log('本次触发的action',action); console.log('改变之前的状态',store.getState()); next(action) console.log('最新的状态',store.getState()); console.log('=================================='); }
2- 第三方中间件
1- redux-logger
npm i redux-logger
// 引入第三方中间件 import {logger} from 'redux-logger' let store = new createStore(rootReducer,applyMiddleware(logger))
2- redux-thunk,能够发起异步请求
npm i redux-thunk
import thunk from 'redux-thunk' let store = new createStore(rootReducer,applyMiddleware(logger,thunk))
export const actions = { changeNameActions:name=>({type:TYPES.CHANGE_ONE_NAME,name}), changeAgeActions:age=>({type:TYPES.CHANGE_ONE_AGE,age}), changePeoActions:peo=>({type:TYPES.CHANGE_ONE_PEO,people:peo}), changeListActions:list=>({type:TYPES.CHANGE_ONE_LIST,list}), getList:()=>{ return (dispatch)=>{ fetch('/api/getcate').then(res=>res.json()).then(res=>{ dispatch({type:TYPES.CHANGE_ONE_LIST,list:res.list}) }) } } }