Hook 实现原理请参考 一文彻底搞懂react hooks的原理和实现

背景

挑选了 2 个最常用以及有代表性的自定义 hooks:

DIY 一个简易的 useRequest

这里模仿 ahooks.js,简单封装下 useRequest 方法

参数是要执行的异步请求函数,返回字段如下:

/*
 * @Author: dongyuanxin
 * @Date: 2021-01-09 23:09:19
 * @Github: <https://github.com/dongyuanxin/blog>
 * @Blog: <https://xin-tan.com/>
 * @Description: 自定义hooks -- useRequest
 */

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";

// 自定义 useRequest Hooks
const useRequest = (req) => {
    const [loading, setLoading] = useState(false);
    const [error, setError] = useState(null);
    const [data, setData] = useState(null);

    const run = async () => {
        if (loading) {
            return;
        }

        setLoading(true);
        try {
            const data = await req();
            setData(data);
        } catch (error) {
            setError(error);
        } finally {
            setLoading(false);
        }
    };

    return {
        loading,
        error,
        data,
        run,
    };
};

下面是使用这个 Hook 的示例:

// 模拟异步请求
const mockData = () => {
    return new Promise((resolve) => {
        const waitMs = Math.floor(Math.random() * 1000);
        console.log(">>> waitMs ", waitMs);
        setTimeout(() => {
            resolve(waitMs);
        }, waitMs);
    });
};

// 下面使用了useRequest来包装异步请求
const App = () => {
    const { run, loading, error, data } = useRequest(mockData);

    useEffect(() => {
        run();
    }, []);

    if (error) {
        return <span>发生错误: {error.message}</span>;
    }

    if (loading || !data) {
        return <span>加载中...</span>;
    }

    return <span>加载完成,数据是:{data}</span>;
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

可以看出来,借助 hooks 的特性,可以将状态和数据的逻辑单独封装,作为可复用的函数提供给开发者使用。

封装的思路也很简单,就是将被认为可以复用的逻辑,提炼到一个 hooks 函数(use 开通命名)中即可。在 UI 函数组件中,直接使用这个 hooks 函数获取状态/动作,进行渲染。

这点有点像 saga-duck.js, 在使用 saga-duck.js 的时候,数据、状态是放在 Duck 文件中维护的,一个 Duck 文件一个类(继承自 BaseDuck)。而 UI 的逻辑是放在 .jsx 中使用。其可以直接使用 Duck 文件中维护的数据和状态。并且 Duck 之间是通过继承和组合的方式,实现逻辑复用。

但使用 saga-duck.js 毕竟对代码有侵入性,现在借助 hooks,就可以简单快速实现同样的逻辑,并且不引入额外维护和学习成本。

Powered by Fruition