三、React全家桶(一)
Reducer
什么是Reducer?
reducer就是一个纯函数,接收旧的 state 和 action,返回新的state
之所以将这样的函数称之为 reducer,是因为这种函数与被传入 Array.prototype.reduce(reducer, ?initialValue) 里的回调函数属于相同的类型。保持 reducer 纯净非常重要。永远不要在 reducer里做这些操作:
- 修改传入的参数
- 执行有副作用的操作,如API请求或路由跳转
- 调用非纯函数,如 Date.now() 或 Math.random()
什么是reduce
const array1 = [1, 2, 3, 4]; // 类似累加:accumulator为total,currentValue为当前value const reducer = (accumulator, currentValue) => accumulator + currentValue; // 1 + 2 + 3 + 4 console.log(array1.reduce(reducer)); // expected output: 10 // 5 + 1 + 2 + 3 + 4 console.log(array1.reduce(reducer, 5)); // expected output: 15
函数聚合
function f1() { console.log("f1"); } function f2() { console.log("f2"); } function f3() { console.log("f3"); }
现在想输出 : f1 f2 f3
方法1:f1();f2();f3();
方法2:f3(f2(f1()))
方法3:
function compose(...funcs){ const len = funcs.length if(len === 0) return arg => arg if(len === 1) return funcs[0] return funcs.reduce((left, right)=>(...args)=>right(left(...args))) } compose(f1,f2,f3)()
Redux上手
import {createStore} from 'redux';
function counterReducer(state=0, action){
// console.log(state);
switch (action.type){
case "add":
return state + 1
default:
return state
}
}
const store = createStore(counterReducer)
export default store
创建 ReduxPage
import React, {Component} from 'react'
import store from '../store/reduxStore';
export default class ReduxPage extends Component {
componentDidMount(){
store.subscribe(()=>{
// console.log('subscribe');
// this.forceUpdate()
this.setState({})
})
}
render() {
// console.log('ReduxPage', store);
return (
<div>
<h1>ReduxPage</h1>
<p>counter:{store.getState()}</p>
<button onClick={() => store.dispatch({type: 'add'})}>add</button>
</div>
)
}
}
检查点
1、createStore 创建 store
2、reducer 初始化、修改状态函数
3、getState 获取状态值
4、dispatch 提交更新
5、subscribe 变更订阅
react-redux
每次都重新调用 render 和 getState 太low了,想用更react的方式来写,需要react-redux的支持
npm install react-redux --save
提供了两个api
1、Provider 为后代组件提供store
2、connect 为组件提供数据和变更方法
全局提供store,index.js
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import store from './store/reactReduxStore'; import {Provider} from 'react-redux'; ReactDOM.render( <Provider store={store}> <App /> </Provider> , document.getElementById('root'));
reactReduxStore.js
import {createStore} from 'redux';
function counterReducer(state=0, action){
// console.log(state);
switch (action.type){
case "add":
return state + 1
case "minus":
return state - 1
default:
return state
}
}
const store = createStore(counterReducer)
export default store
ReactReduxPage.js
import React, { Component } from 'react'
import {connect} from 'react-redux';
class ReactReduxPage extends Component {
render() {
console.log(this.props);
const {counter, add, minus} = this.props
return (
<div>
<h1>ReactReduxPage</h1>
<p>counter:{counter}</p>
<button onClick={add}>add</button>
<button onClick={minus}>minus</button>
</div>
)
}
}
export default connect(
// mapStateToProps
state=>{
return {counter: state}
},
// mapDispatchToProps
{
add: ()=>{
return {
type: 'add'
}
},
minus: ()=>{
return {
type: 'minus'
}
}
}
)(ReactReduxPage)
异步
Redux只是个纯粹的状态管理器,默认只支持同步,实现异步任务 比如延迟、网络请求,需要中间件的支持,比如我们试用最简单的redux-thunk和redux-logger
npm install redux-thunk redux-logger --save
应用中间件,store.js
import {createStore, applyMiddleware} from 'redux';
import logger from "redux-logger"
import thunk from "redux-thunk";
const store = createStore(counterReducer, applyMiddleware(logger, thunk))
使用异步操作时的变化,ReduxTest.js
const mapDispatchToProps = { add: ()=>{ return { type: 'add' } }, minus: ()=>{ return { type: 'minus' } }, asyAdd: () => dispatch =>{ setTimeout(() => { // 异步结束后,手动调用 dispatch dispatch({ type: 'add' }) }, 1000); } }
代码抽取
抽离reducer和action
1、抽离action
action/reactReduxPage.js
export const add = ()=>{ return { type: 'add' } } export const minus= ()=>{ return { type: 'minus' } } export const asyAdd= () => dispatch =>{ setTimeout(() => { // 异步结束后,手动调用 dispatch dispatch({ type: 'add' }) }, 1000); }
// 对应的ReactReduxPage文件直接引用
2、抽离reducer
store/counterReducer.js
export default function counterReducer(state=0, action){ // console.log(state); switch (action.type){ case "add": return state + 1 case "minus": return state - 1 default: return state } }
reactReduxStore.js调用
import {createStore, applyMiddleware} from 'redux';
import logger from "redux-logger"
import thunk from "redux-thunk";
import counterReducer from './counterReducer';
const store = createStore(counterReducer, applyMiddleware(logger, thunk))
export default store
如果有多个中间件 --- combineReducers
reactReduxStore.js
import {createStore, applyMiddleware, combineReducers} from 'redux';
import logger from "redux-logger"
import thunk from "redux-thunk";
import counterReducer from './counterReducer';
import counterReducer2 from './counterReducer';
// 如果有多个中间件,则用combineReducers
const store = createStore(
combineReducers({
counter: counterReducer,
counter2: counterReducer2
}),
applyMiddleware(logger, thunk)
)
export default store
ReactReduxPage.js做出修改
const mapStateToProps = state => { console.log(state); // {counter: 0, counter2: 0} // return需要做修改 // return { counter: state } return { counter: state.counter } }
Redux拓展
redux核心实现:
- 存储状态state
- 获取状态getState
- 更新状态dispatch
MyReduxPage.js
import React, {Component} from 'react'
import store from '../../store/MyReduxStore'; // 这里做出了修改
export default class MyReduxPage extends Component {
componentDidMount(){
store.subscribe(()=>{
this.setState({})
})
}
render() {
return (
<div>
<h1>ReduxPage</h1>
<p>counter:{store.getState()}</p>
<button onClick={() => store.dispatch({type: 'add'})}>add</button>
<button onClick={() => store.dispatch({type: 'minu'})}>minu</button>
</div>
)
}
}
MyReduxStore.js
import {createStore} from '../kRedux';
function counterReducer(state=0, action){
// console.log(state);
switch (action.type){
case "add":
return state + 1
case "minu":
return state - 1
default:
return state
}
}
const store = createStore(counterReducer)
export default store
kRedux.js
export function createStore(reducer){ let currentState = undefined let currentListeners = [] function getState(){ return currentState } function dispatch(action){ currentState = reducer(currentState, action) currentListeners.map(cl=>cl()) } function subscribe(listener){ currentListeners.push(listener) } dispatch({type: '@IMOOC/REDUX'}) // 这里随意写type值,本意是要初始化执行一次 return { getState, dispatch, subscribe } }
中间件实现
kRedux.js
export function createStore(reducer, enhancer){ if(enhancer){ // 判断是否有增强器(中间件) return enhancer(createStore)(reducer) } let currentState = undefined let currentListeners = [] function getState(){ return currentState } function dispatch(action){ currentState = reducer(currentState, action) currentListeners.map(cl=>cl()) } function subscribe(listener){ currentListeners.push(listener) } dispatch({type: '@IMOOC/REDUX'}) // 这里随意写type值,本意是要初始化执行一次 return { getState, dispatch, subscribe } } // 中间件 export function applyMiddleware(...middlewares) { return createStore => (...arg) => { const store = createStore(...arg) const midApi = { getState: store.getState, dispatch: store.dispatch } const chain = middlewares.map(mw=>mw(midApi)) const dispatch = compose(...chain)(store.dispatch) return { ...store, dispatch } } } function compose(...funcs){ const len = funcs.length if(len === 0) return arg=>arg if(len === 1) return funcs[0] return funcs.reduce((left, right)=>(...args)=>right(left(...args))) }
MyReduxStore.js
import {createStore, applyMiddleware} from '../kRedux';
function counterReducer(state=0, action){
// console.log(state);
switch (action.type){
case "add":
return state + 1
case "minu":
return state - 1
default:
return state
}
}
const store = createStore(counterReducer, applyMiddleware(logger))
export default store
function logger({dispatch, getState}){
return dispatch=>action=>{
console.log(action.type + "执行了~");
return dispatch(action)
}
}

浙公网安备 33010602011771号