深入学习react(一) 写个自己的redux

src=http___imgcdn.sdk.cn_article_axWWqwMzZ-hrJHcG-VKj.png&refer=http___imgcdn.sdk.jpg

一、redux及其源码

不知不觉从vue转到react已经一年了,对于react的认识也从使用迈向了原理,本着学习的态度,写下这个系列,希望大神多多指点,也希望能给学弟学妹们带来一丝丝帮助。

1、初始化项目

首先让我们先初始化一下我们的项目,控制台执行:
npx create-react-app myName
其中myName是我们的项目名称可以随意根据自己的喜好命名,然后回车,这时候默默等待安装完毕即可

2、初始化页面目录配置

我这里删除了一些不必要的默认文件,您可以根据自己需求做优化:

1:在src目录下新建pages,store文件夹,在pages下新建index.jsx文件,在store文件夹下新建store.js文件

2:执行npm install --save redux安装redux

3:让我们使用先使用一下redux吧:

index.jsx完整代码

import React, { Component } from 'react'

import store from '@/store/store'

export default class index extends Component {
    componentDidMount() { 
        // 订阅,默认取调用一下react的forceUpdate方法,从新render一下
        store.subscribe(() => { 
            this.forceUpdate()
        })
    }
    add = () => {
        store.dispatch({type:"ADD"})
    }
    minus = () => { 
        store.dispatch({type:"MINUS"})
    }
    render() {
        return (
            <div className="le_home">
                redux源码学习
                <p>{store.getState()} </p>
                <button onClick={ this.add}>增加</button>
                <button onClick={ this.minus}>减少</button>
            </div>
        )
    }
}
复制代码

store下完整代码:

import { createStore } from 'redux'
function countReducer(state = 0, action) { 
    switch (action.type) {
        case 'ADD':
            return state+1
        case 'MINUS':
            return state-1
        default:
            return state
    }
}

let store = createStore(countReducer)

export default store
复制代码

项目运行后我们点击按钮就可以看到数字的变化了,是不是很申请啊,下面让我们去发现一下redux的神秘吧!

3、在store文件夹下面创建myStore.js文件,这是我们自己的redux

一:先分析下createStore函数的结构

1:接收了一个参数(reducer)

2:有三个内置的方法,分别是subscribe(订阅),dispatch(派发),getState(获取)

二:这里我直接给出了代码,有详细的注释

export function createStore(reduce,enhancer) { 
    if (enhancer) { 
        return enhancer(createStore(reduce))
    }
    // 定义初始值
    let currentData = undefined
    // 保存监听函数
    let currentLinser = []
    // 获取值
    function getState() { 
        return currentData
    }
    // 派发值
    function dispatch(action) { 
        currentData = reduce(currentData, action)
        currentLinser.forEach(a=>a())
    }
    // 订阅值,这里调用react的forceUpdate()方法让render从新渲染
    function subscribe(cb) { 
        currentLinser.push(cb)
    }
    // 初始化的时候先派发一下就可以了,因为我们订阅的时候直接返回了初始值
    dispatch({type:'dsfs'})
    return {
        getState,
        dispatch,
        subscribe
    }
}
复制代码

好了到这里我们就完成了redux的基本功能了,是不是很简单啊

4、redux中间件

上面我们实现的redux是有一定的缺陷的,就是我们在派发的时候直接处理了action,无法去做一些逻辑的编写,那么如何优化这一现象呢,这时就需要redux的第二个重要函数applyMiddleware了,下面让我们一起实现下吧

首先让我们安装以下react-thunk中间件,并且使用它看看会发生什么吧!
控制台执行npm install --save react-thunk

1:在store.js代码下增加

import { createStore,applyMiddleware } from 'redux'
import thunk from "redux-thunk";
let store = createStore(countReducer,applyMiddleware(thunk))
复制代码

2:在index,jsx代码下增加

//修改add函数增加一些逻辑
add = () => { 
    store.dispatch(dispatch => { 
        //这里就可以任意挥发了
        setTimeout(() => { 
            dispatch({type:"ADD"})
        },1000)
    })
}
复制代码

5、applyMiddleware函数的实现

在myStore.js下创建applyMiddleware函数

export function applyMiddleware(...middlewares) {
    // 直接返回一个强化后的函数
    return createStore => (...args) => {
        const store = createStore(...args)
        let dispatch = store.dispatch
        const midApi = {
            getState:store.getState,
            dispatch:(...args)=>dispatch(...args)
        }
        // 获取状态值,派发action
        const middlewareChain = middlewares.map(middleware => middleware(midApi))
        // 聚合成一个函数,这里是一个经典责任链设计模式
        dispatch = compose(...middlewareChain) (store.dispatch)
        return {
            ...store,
            dispatch
        }
    }
}
//聚合函数
export function compose(...funcs) {
    if (funcs.length === 0) {
        return arg => arg
    }
    if (funcs.length === 1) {
        return funcs[0]
    }
    数据reduce方法,不清楚的可以查阅一下,一是从左往右计算值,二是聚合函数
    return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
复制代码

这里就基本实现了redux,是不是很简单啊,下面我就就要开始学习react-redux了,加油!!!

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享