react-redux简易实现

刚刚写了一半还是删了,因为我贴了好多代码,我感觉还是思路最重要,所以代码就放在最后的github地址了

以下是正文

react-redux

我们都知道react-redux是处理状态管理的,它把状态放在了一个全局的唯一的对象里面
这个对象需要提供

  • 获取这个对象的方法-getstate
  • 需要提供可以改变状态的方法-dispatch
  • 需要在状态改变的时候通知订阅这个状态的组件方法 -subscribe

当我创建完成这个对象之后,我们需要

  • 把这个对象传给子孙后代,所以需要Provider
  • 子孙后代要用怎么办?所以要connect,但是子代不需要所有的状态和改变状态的方法,所以有了mapStateToProps和mapDispatchToProps

实现Provider可以用context api来实现

connect实际上是一个高阶组件,使用方法是connect(子组件需要的state,子组件需要的改变状态的方法,子组件本身)

  • 在connect里把全局状态和改变state方法根据传过来的mapstatetoprops和mapdispatchtoprops进行过滤
  • 把子组件需要的传给子组件之后返回子组件

中间件

中间件是为了我们在发出action和dispatch之前做一些我们自己想做的事情,比如说打印日志,改造dispatch接收的参数等等
中间件的作用是返回一个全新的store,它的dispatch被增强了

下面是创建带有中间件的store

const store = createStore(
  reducer,
  applyMiddleware(thunk,promise)
);

所以

  • 需要改造原来的createStore方法,如果有中间件这个增强器,就使用增强版的store
  • 在applyMiddleware函数里面把所有的中间件聚合,让原来的dispatch得到增强,实现如可以接受函数或者promise对象作为参数

中间件与其说是技术,不如说是一种思想,顾名思义,在A和B之间做一些事情,从而满足我们的需求

完整代码地址:https://github.com/dz333333/toy-redux

ps:我在实现redux的时候发现他是使用发布订阅的模式,在实现subscribe的时候让我想起了我之前写的vue双向绑定里reactive里proxy在set的时候需要执行一些副作用effect,都需要收集依赖,然后redux是坚持单项数据流,数据不可变,reducer只能是纯函数,但是mobx却是双向绑定,在组件里就可以直接改变全局状态,我就想mobx是不是用proxy也可以实现,一通瞎想之后,感觉有些东西真的都是通了,原来如此的感觉,以前设计模式也不在意,这次才发现发布订阅是如此的常用,vue在用,mobx也可以用,以后要多学习学习了

react-router简易实现

react-router

利用context hashchange 实现router

大致思路如下

  • 利用context保证唯一路由信息,以及传递路由信息
  • 监听hashchange 修改当前路由信息

ps 以下代码都是基于hooks,而且只实现了HashRouter,如果要实现BrowserRouter就要监听popstate事件

//HashRouter.js
import React, { useState, useEffect } from 'react';
import Context from "./context";
const HashRouter = (props) => {
const [location,setLocation]=useState({
    pathname: window.location.hash.slice(1) || "/", // 获取浏览器地址栏中的hash值,如果不存在则默认为"/"
    query: undefined
})
useEffect(()=>{
    window.addEventListener("hashchange", () => { // 监听浏览器地址栏hash值变化
        setLocation(
            {
                ...location,
                pathname: window.location.hash.slice(1) // 更新pathname
            }
        )
    });
},[])
const currentRoute = {
    location: location, 
    history: { // 新增一个history对象用于实现当前路由的切换
        push: (to) => {
            if (typeof to === "object") { // 如果to是一个对象
                let { pathname, query } = to; // 取出pathname和query
                window.location.hash = pathname; // 更新浏览器hash值,触发浏览器hashchange事件
                location.query = query; // 更新query
            } else { // 修改浏览器地址栏的hash值
                window.location.hash = to; // 更新浏览器hash值
            }
        }
    }
}
return (
    <Context.Provider value={currentRoute}>
        {props.children}
    </Context.Provider>
);
};
export default HashRouter;

//Route.js
import React, {useContext} from "react";
import Context from "./context";
const Route = (props) => {
const context=useContext(Context)
const currentRoutePath = context.location.pathname; // 从上下文中获取到当前路由的路径
const {path, component:Component} = props; // 获取给Route组件传递的props属性
const props2 = {
    ...context
}
if (currentRoutePath === path) {
    return (
        <Component {...props2}></Component>
    );
}
return null
};
export default Route;

完整代码地址:https://github.com/dz333333/toy–router
参考:https://segmentfault.com/a/1190000022250917