使用react hooks实现自己的context-redux

栏目: IOS · Android · 发布时间: 6年前

内容简介:首发自注:如要运行本文的代码,请先确认自己的react版本已支持hooksreact hooks出来已经有段时间了,本文不对hooks的具体用法作介绍,而是使用hooks实现一个简易的基于context的redux

首发自 我的github博客 ,欢迎star

注:如要运行本文的代码,请先确认自己的react版本已支持hooks

react hooks出来已经有段时间了,本文不对hooks的具体用法作介绍,而是使用hooks实现一个简易的基于context的redux

使用useReducer实现初版redux

React hooks自带了useReducer供我们使用,它接受两个参数,一是reducer函数,二是初始state,并返回state和dispatch函数,如下

const [state, dispatch] = useReducer(reducer, initialState);

这个函数自己实现的话也不难,如下:

const useMyReducer = (reducer, initialState) => {
    const [state, setState] = useState(initialState);
    const dispatch = action => {
        const newState = reducer(action, state);
        setState(newState);
    };
    return [state, dispatch];
};

即将initialState作为state的初始状态传入useState,dispatch则是一个函数,它会将接受的action和state传给reducer,并获取reducer的返回值赋给state

我们先利用useReducer实现一个计数器的简单页面

reducer函数和initialState如下:

const initialState = {
    count: 0
};

const reducer = (state, action) => {
    switch (action.type) {
        case "increase":
            return { ...state, count: state.count + 1 };
        case "decrease":
            return { ...state, count: state.count - 1 };
        default:
            return state;
    }
};

计数器组件:

const Demo = () => {
    const [state, dispatch] = useReducer(reducer, initialState); 
    return (
        <div>
            counter:{state.count}
            <div>
                <button
                    onClick={() => {
                        dispatch({ type: "increase" });
                    }}
                >
                    increase
                </button>
                <button
                    onClick={() => {
                        dispatch({ type: "decrease" });
                    }}
                >
                    decrease
                </button>
            </div>
        </div>
    );
};

这就是初版的redux了,但这个redux有些问题,就是它的state和dispatch是属于自己的,其他组件并不能拿到,也就是说,如果我们的页面有两个Demo组件,它们的state是各自独立,互不影响的

将state和dispatch存在context中

为了解决上述问题,我们必须拥有一个全局状态,并将state和dispatch放入这个全局状态中。这里,我们选用context作为我们的全局状态,context在旧版React中不推荐使用,但在改进之后,官方开始推荐大家使用

我们先创建一个context:

const context = React.createContext();

为了各个组件都能拿到context的数据,我们需要有一个Provider组件包在最外层:

const Provider = props => {
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <context.Provider value={{ state, dispatch }}>
            {props.children}
        </context.Provider>
    );
};

我们将useReducer返回的state、dispatch传入context.Provider中,让它的children都能拿到

然后,我们像下面一样用Provider包在组件外层:

<Provider>
    <Demo />
    <Demo />
</Provider>

我们删去计数器Demo组件中的:

const [state, dispatch] = useReducer(reducer, initialState);

加上通过useContext函数拿到context上的数据:

const { state, dispatch } = useContext(context);

要注意的是,传入useContext函数的context必须是我们之前通过 React.createContext() 创建的context

这样,即使是两个Demo组件,它们也是共用一份数据了

解决异步的问题

很显然,现在的context-redux和单纯的redux一样,只能dispatch一个对象,也就是说,这个dispatch操作是同步的,如果我们要做异步的操作呢?很简单,我们借鉴redux-thunk的方法,让dispatch可以接受函数参数

改造Provider函数组件如下:

const Provider = props => {
    const [state, origin_dispatch] = useReducer(reducer, initialState);
    const dispatch = action => {
        if (typeof action === "function") {
            return action(origin_dispatch);
        }
        return origin_dispatch(action);
    };
    return (
        <context.Provider value={{ state, dispatch }}>
            {props.children}
        </context.Provider>
    );
};

我们将userReducer函数返回的原始dispath命名为 origin_dispatch ,自定义dispatch函数,当action为函数的时候,我们执行action函数,并将 origin_dispatch 当作参数传进去;action不是函数,直接调用 origin_dispatch ,不做处理

我们测试一下:

const sleep = wait => {
    return new Promise(resolve => {
        setTimeout(() => resolve(), wait);
    });
};
const increaseCount = async dispatch => {
    await sleep(1000);
    dispatch({ type: "increase" });
};
<button
    onClick={() => {
        dispatch(increaseCount);
    }}
    >
    increase
</button>

increaseCount 是一个异步函数,我们将它当作参数传入我们封装的新dispatch中,点击increase按钮,1s之后,计数器的数字加1,至此,我们的context-redux也支持dispatch异步操作了

最后

本文的代码,我放在了自己的github上,这是 传送门


以上所述就是小编给大家介绍的《使用react hooks实现自己的context-redux》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Web Analytics 2.0

Web Analytics 2.0

Avinash Kaushik / Sybex / 2009-10-26 / USD 39.99

The bestselling book Web Analytics: An Hour A Day was the first book in the analytics space to move beyond clickstream analysis. Web Analytics 2.0 will significantly evolve the approaches from the fir......一起来看看 《Web Analytics 2.0》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

在线进制转换器
在线进制转换器

各进制数互转换器

MD5 加密
MD5 加密

MD5 加密工具