You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React自定义Hook中统一归集返回多个内部函数

React自定义Hook函数统一归集返回实现

原有代码

Main.tsx

import React from "react";
import { useRectangleControls } from "src/useRectangleControls";

export function Main() {
    const rectangleRef = React.useRef<HTMLDivElement>(null);
    const mainControls = useRectangleControls(rectangleRef);

    React.useEffect(() => {
        console.log(mainControls.isMouseInRectangle);
    }, [mainControls.isMouseInRectangle]);

    return (
        <div className="w-full h-screen flex items-center justify-center">
            <div className="w-[60%] h-[30%] bg-green-900" ref={rectangleRef} onMouseEnter={mainControls.onMouseEnter} onMouseLeave={mainControls.onMouseLeave}></div>
        </div>
    );
}

上述组件渲染一个可交互矩形,矩形颜色会根据鼠标悬停状态动态切换。原本鼠标进入、离开的事件逻辑已经抽离到自定义HookuseRectangleControls中,原有Hook实现如下:

import React from "react";

export function useRectangleControls(rectangleRef: React.RefObject<HTMLDivElement>) {
    const [isMouseInRectangle, setIsMouseInRectangle] = React.useState(false);

    function onMouseEnter() {
        if (rectangleRef.current) {
            setIsMouseInRectangle(true);
            rectangleRef.current.classList.remove("bg-green-900");
            rectangleRef.current.classList.add("bg-red-900");
        }
    }
    function onMouseLeave() {
        if (rectangleRef.current) {
            setIsMouseInRectangle(false);
            rectangleRef.current.classList.remove("bg-red-900");
            rectangleRef.current.classList.add("bg-green-900");
        }
    }


    return { onMouseEnter, onMouseLeave, isMouseInRectangle };
}

需求说明

把Hook内部定义的所有控制函数归集到单个rectangleControls变量中统一返回,返回语句固定为return {rectangleControls, isMouseInRectangle},后续往useRectangleControls新增函数时,不需要每次修改return语句。

实现代码

修改后的useRectangleControls Hook

import React from "react";

export function useRectangleControls(rectangleRef: React.RefObject<HTMLDivElement>) {
    const [isMouseInRectangle, setIsMouseInRectangle] = React.useState(false);

    // 所有事件控制函数统一归集到该对象
    const rectangleControls = React.useMemo(() => ({
        onMouseEnter() {
            if (rectangleRef.current) {
                setIsMouseInRectangle(true);
                rectangleRef.current.classList.remove("bg-green-900");
                rectangleRef.current.classList.add("bg-red-900");
            }
        },
        onMouseLeave() {
            if (rectangleRef.current) {
                setIsMouseInRectangle(false);
                rectangleRef.current.classList.remove("bg-red-900");
                rectangleRef.current.classList.add("bg-green-900");
            }
        }
        // 后续新增控制函数直接在这个对象内部添加即可,无需修改return语句
    }), [rectangleRef]);

    return { rectangleControls, isMouseInRectangle };
}

对应调整后的Main.tsx

因为返回结构变了,组件侧取值需要对应调整:

import React from "react";
import { useRectangleControls } from "src/useRectangleControls";

export function Main() {
    const rectangleRef = React.useRef<HTMLDivElement>(null);
    const { rectangleControls, isMouseInRectangle } = useRectangleControls(rectangleRef);

    React.useEffect(() => {
        console.log(isMouseInRectangle);
    }, [isMouseInRectangle]);

    return (
        <div className="w-full h-screen flex items-center justify-center">
            <div
                className="w-[60%] h-[30%] bg-green-900"
                ref={rectangleRef}
                onMouseEnter={rectangleControls.onMouseEnter}
                onMouseLeave={rectangleControls.onMouseLeave}
            ></div>
        </div>
    );
}

实现说明

  • 用React.useMemo包裹rectangleControls对象,依赖传入rectangleRef,可以保证非必要场景下对象引用稳定,避免每次渲染生成新对象导致不必要的重渲染。
  • 后续新增比如onClick、onMouseMove这类矩形控制逻辑时,只需要在rectangleControls对象内部新增对应方法即可,不需要改动最后的return语句,完全符合需求。

内容的提问来源于stack exchange,提问作者swamp blues

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 05:45:06