Custom React Hook: Use Color on Mouse Move
This powerful configurable hook returns a color based on the mouse's x and y coordinates.
Posted on November 16, 2022
Watch the related tutorial on Full Stack Craft's YouTube!
React Hooks
React Hooks are extremely powerful - they allow you to build reactive code that can dropped into as many components as you want, all in one line. In this code walk-through, we'll be building a hook that returns a color based on the mouse's x and y coordinates. We'll first build a naïve implementation that gets the job done, but leaves many functionalities to be desired.
A Naive Implementation of the Hook
With our defined idea, we can already get started. Let's allow two colors that we want
Altogether, our initial implementation of this hook looks like this:
import { useCallback, useEffect, useRef, useState } from "react"
import chroma from "chroma-js"
export type ArrayOfTwoOrMore<T> = {
0: T
1: T
} & Array<T>
// this function takes the current x and y coordinates of the mouse and produces a color based on them
export const useColorOnMouseMove = (colors: ArrayOfTwoOrMore<string>) => {
const [color, setColor] = useState<string>(colors[0])
const maxX = useRef(0)
const maxY = useRef(0)
const scale = chroma.scale([colors[0], colors[1]])
const onMouseMove = useCallback(
(e: MouseEvent) => {
if (maxX.current > 0 && maxY.current > 0) {
const percentX = e.clientX / maxX.current
const percentY = e.clientY / maxY.current
const average = (percentX + percentY) / 2
const color = scale(average).hex()
setColor(color)
}
},
[scale]
)
const onResize = () => {
maxX.current = window.innerWidth
maxY.current = window.innerHeight
}
useEffect(() => {
window.addEventListener("mousemove", onMouseMove)
window.addEventListener("resize", onResize)
return () => {
window.removeEventListener("mousemove", onMouseMove)
}
}, [onMouseMove])
return color
}
Adding Various Improvements
What we've built so far "works", but in my opinion the hook needs a few improvements:
- More color interpolation algorithms - change in X only, change in Y only, radial
- What if the user doesn't want to use the whole background? Ideally the user could pass a ref to define which dimensions to use to calculate the color change
- What about multiple colors and coordinates?
- Performance issues, directly updating state every time the browser
We'll address each of these points in the next sections.