三、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上手
Redux是JavaScript应用的状态容器。它保证程序行为一致性且易于测试。
安装redux: npm install redux --save
用一个累加器举例:
1、需要一个store来存储数据
2、store里的reducer初始化state并定义state修改规则
3、通过dispatch一个action来提交对数据的修改
4、action提交到reducer函数里,根据传入的action的type,返回新的state
创建store ,src/store/ReduxStore.js
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文件直接引用
import React, { Component } from 'react'
import {connect} from 'react-redux';
import {add, minus,asyAdd} from '../action/reactReduxPage'; // 此处直接引用
class ReactReduxPage extends Component {
render() {
console.log(this.props);
const {counter, add, minus, asyAdd} = this.props
return (
<div>
<h1>ReactReduxPage</h1>
<p>counter:{counter}</p>
<button onClick={add}>add</button>
<button onClick={minus}>minus</button>
<button onClick={asyAdd}>asyAdd</button>
</div>
)
}
}
const mapStateToProps = state => {
return {
counter: state
}
}
const mapDispatchToProps = {
add,
minus,
asyAdd
}
export default connect(
// mapStateToProps
mapStateToProps,
// mapDispatchToProps --- 直接引用
mapDispatchToProps
)(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)
}
}
以上是 三、React全家桶(一) 的全部内容, 来源链接: utcz.com/z/382924.html