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} onm ouseEnter={mainControls.onMouseEnter} onm ouseLeave={mainControls.onMouseLeave}></div>
</div>
);
}
The above component returns a rectangle. The color of the rectangle depends on the mouse position. The event handlers for onMouseEnter
and onMouseLeave
were shifted to a custom hook called useRectangleControls:
import React from "react";
export function useRectangleControls(rectangleRef: React.RefObject<HTMLDivElement>) {
const [isMouseInRectangle, setIsMouseInRectangle] = React.useState(false);
function onm ouseEnter() {
if (rectangleRef.current) {
setIsMouseInRectangle(true);
rectangleRef.current.classList.remove("bg-green-900");
rectangleRef.current.classList.add("bg-red-900");
}
}
function onm ouseLeave() {
if (rectangleRef.current) {
setIsMouseInRectangle(false);
rectangleRef.current.classList.remove("bg-red-900");
rectangleRef.current.classList.add("bg-green-900");
}
}
return { onm ouseEnter, onm ouseLeave, isMouseInRectangle };
}
I want to collect all functions and return them in one variable. I want the return statement to look something like this: return {rectangleControls, isMouseInRectangle}
where rectangleControls
contains all functions inside the useRectangleControls
custom hook.
My goal is to avoid updating the return statement each time I add a new function to useRectangleControls
CodePudding user response:
You can do that in the following way
import React from "react";
export interface Indexable<T = any> {
[key: string]: T|undefined;
}
export interface RectangleControls {
onm ouseEnter: () => void;
onm ouseLeave: () => void;
}
export function useRectangleControls(rectangleRef: React.RefObject<HTMLDivElement>) {
const [isMouseInRectangle, setIsMouseInRectangle] = React.useState(false);
// const rectangleControls: Indexable = {}; // one approach for typescript
const rectangleControls: RectangleControls = {
onm ouseEnter: () => {},
onm ouseLeave: () => {}
}; // second approach for typescript
rectangleControls.onMouseEnter = () => {
if (rectangleRef.current) {
setIsMouseInRectangle(true);
rectangleRef.current.classList.remove("bg-green-900");
rectangleRef.current.classList.add("bg-red-900");
}
}
rectangleControls.onMouseLeave = () => {
if (rectangleRef.current) {
setIsMouseInRectangle(false);
rectangleRef.current.classList.remove("bg-red-900");
rectangleRef.current.classList.add("bg-green-900");
}
}
return { rectangleControls, isMouseInRectangle };
}
Edit: Explaining the changes made in the hook. Here I have created an Object rectangleControls and converted the onm ouseEnter, onm ouseLeave to arrow function and assign them as key to rectangleControls, this will help you achieve what you are looking for exporting a single variable.
CodePudding user response:
You will just need to import your custom hook useRectangleControls
inside the component where you're going to use it. then use the onMouseEnter, onm ouseLeave, isMouseInRectangle
from it like so.
const { onm ouseEnter, onm ouseLeave, isMouseInRectangle } = useRectangleControls(pass your params here);
don't forget to import it from its location.
for example:
import useRectangleControls from "./hooks/useRectangleControls";
That's it.