Remove synchronous setstate call in hover check

This commit is contained in:
Sam Becker 2025-10-26 11:00:09 -05:00
parent ff9fc94ce1
commit 70abf8178d
6 changed files with 24 additions and 17 deletions

View File

@ -20,7 +20,7 @@ const eslintConfig = defineConfig([
rules: {
// Temporarily disable during Next.js 16 migration
'react-hooks/refs': 'off',
'react-hooks/set-state-in-effect': 'off',
'react-hooks/set-state-in-effect': 'warn',
'@next/next/no-img-element': 'off',
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/no-require-imports': 'off',

View File

@ -30,6 +30,8 @@ export type AppStateContextType = {
categoriesWithCounts?: Awaited<ReturnType<
typeof getCountsForCategoriesCachedAction
>>
// ENVIRONMENT
supportsHover?: boolean
// MODAL
isCommandKOpen?: boolean
setIsCommandKOpen?: Dispatch<SetStateAction<boolean>>

View File

@ -40,6 +40,7 @@ import {
SWRKey,
} from '@/swr';
import { warmRedisAction } from './actions';
import useSupportsHover from '@/utility/useSupportsHover';
export default function AppStateProvider({
children,
@ -78,6 +79,8 @@ export default function AppStateProvider({
}, [nextPhotoAnimationId, setNextPhotoAnimation]);
const [shouldRespondToKeyboardCommands, setShouldRespondToKeyboardCommands] =
useState(true);
// ENVIRONMENT
const supportsHover = useSupportsHover();
// MODAL
const [isCommandKOpen, setIsCommandKOpen] =
useState(false);
@ -229,6 +232,8 @@ export default function AppStateProvider({
shouldRespondToKeyboardCommands,
setShouldRespondToKeyboardCommands,
categoriesWithCounts,
// ENVIRONMENT
supportsHover,
// MODAL
isCommandKOpen,
setIsCommandKOpen,

View File

@ -3,11 +3,11 @@
import { ReactNode, useRef, useState, ComponentProps } from 'react';
import * as Tooltip from '@radix-ui/react-tooltip';
import MenuSurface from './MenuSurface';
import useSupportsHover from '@/utility/useSupportsHover';
import clsx from 'clsx/lite';
import useClickInsideOutside from '@/utility/useClickInsideOutside';
import KeyCommand from './KeyCommand';
import { clearGlobalFocus } from '@/utility/dom';
import { useAppState } from '@/app/AppState';
export default function TooltipPrimitive({
content: contentProp,
@ -51,7 +51,7 @@ export default function TooltipPrimitive({
const [isOpen, setIsOpen] = useState(false);
const supportsHover = useSupportsHover();
const { supportsHover } = useAppState();
const includeButton = supportMobile && supportsHover === false;

View File

@ -2,8 +2,8 @@
import { ReactNode, useRef, useEffect } from 'react';
import { SharedHoverProps, useSharedHoverState } from '../shared-hover/state';
import useSupportsHover from '@/utility/useSupportsHover';
import clsx from 'clsx/lite';
import { useAppState } from '@/app/AppState';
export default function SharedHover({
hoverKey: key,
@ -28,6 +28,8 @@ export default function SharedHover({
}) {
const ref = useRef<HTMLDivElement>(null);
const { supportsHover } = useAppState();
const {
showHover,
dismissHover,
@ -37,8 +39,6 @@ export default function SharedHover({
const isHovering = isHoverBeingShown?.(key);
const supportsHover = useSupportsHover();
useEffect(() => {
const trigger = ref.current;
return () => dismissHover?.(trigger);

View File

@ -1,18 +1,18 @@
import { useState, useEffect } from 'react';
import { useState, useEffect, useRef } from 'react';
export default function useSupportsHover() {
const [supportsHover, setSupportsHover] = useState<boolean>();
const mqlRef = useRef(typeof window !== 'undefined'
? window.matchMedia('(hover: hover)')
: undefined);
const [supportsHover, setSupportsHover] =
useState<boolean>(mqlRef.current?.matches ?? false);
useEffect(() => {
const mql = window.matchMedia('(hover: hover)');
setSupportsHover(mql.matches);
const listener = (e: MediaQueryListEvent) => {
setSupportsHover(e.matches);
};
mql.addEventListener('change', listener);
return () => mql.removeEventListener('change', listener);
const listener = (e: MediaQueryListEvent) => setSupportsHover(e.matches);
const mql = mqlRef.current;
mql?.addEventListener('change', listener);
return () => mql?.removeEventListener('change', listener);
}, []);
return supportsHover;