如何在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
相关产品推荐
相关产品推荐

