Open jeremy-code opened 2 months ago
Related: #30716
Try this
import { useRef, useState, useEffect } from "react";
const UNINITIALIZED = Symbol("UNINITIALIZED");
export const useOnce = <T,>(initialValue: T | (() => T)) => { const ref = useRef < T | typeof UNINITIALIZED > (UNINITIALIZED); const [value, setValue] = useState < T | typeof UNINITIALIZED > (UNINITIALIZED);
useEffect(() => { if (ref.current === UNINITIALIZED) { const resolvedValue = typeof initialValue === "function" ? initialValue() : initialValue; ref.current = resolvedValue; setValue(resolvedValue); } else { setValue(ref.current); } }, [initialValue]);
return value; };
export default function MyApp() { return
State Initialization: Added a state value to store the initialized value.
useEffect: The ref is now initialized inside the useEffect hook, which sets the value both in the ref and in the state.
Return Value: The hook returns the state value, ensuring that the initial render doesn't access ref.current
Thanks for posting. This is a known limitation of the new linter.
i also run into the problem in a different scenario:
when passing the ref object to a custom hook the compiler is not optimizing my code. if i remove the ref
access it works as expected.
// pass the ref object to a custom hook and it is preventing the optimizations.
const mergedRefs = useMergedRef<HTMLDivElement>(ref, setPopperElement);
Do you deprecated to use useRef
? if not, how to use it?
const panelRef = useRef<HTMLDivElement>(null);
const width = panelRef.current?.clientWidth ?? 256; // eslint error here
Is there any available workaround for this? This limitation also affects the useImperativeHandle.
To anyone encountering optimization issues with the usage of useImperativeHandle
, you can place the forwardedRef
inside a useState
hook.
const [refs] = useState(() => {
return { forwardedRef };
});
This works against latest experimental release (0.0.0-experimental-4e0eccf-20240830). It probably breaks the rules, but so far didn't encounter serious issues.
built an app to get paid for this PR https://www.n0va-io.com/discover/facebook/react
I think this is addressed in 19.0.0-beta-8a03594-20241020
. I have a hook that looks like this:
export function useLogger(name: string) {
const loggerRef = useRef<Logger>(null);
if (loggerRef.current === null) {
loggerRef.current = new Logger(name);
}
return loggerRef.current;
}
The linter rule complains only about that .current
in the return statement. However, the conditional needs to have exactly this form of fooRef.current === null
, otherwise the rule will report a false positive.
What kind of issue is this?
Link to repro
https://playground.react.dev/#N4Igzg9grgTgxgUxALhAHRFMCAEcA2AlggHYAuGA3GiTYQLYAOEMZOwOWCASggGY4Avjj4wI9HBhgIAhnAohqtEnAgkwbAKoA5AJJ6AKroCCAGV0AtAKIARHAF4cAZQCe9AEYR8ACgw79ukZmlrYYAJRKNAgAHsyseGoanNgA8iq4jgA8BgA0AHzehCSEZIQy+ABq5VAIyDgGOAA+ON7eYQ559WHt9p3ANDgJ6mzSAo5cvAKZ9U04ZC6MCBAC-oYm5tZ2nd6rgeshNhE0AziEAt6jAHRwsNLkDvaOu0Ebtu39JIODVzcwd2yOeaLZanYqlcpVfA1B6ODB8KAqUpqDA4AD8oJKZUq1QQbRwdSKmIhOKUg0Ex0+OGkZFgnx+t1IZCUgkiJBicTYABN+DIoPg2PDEYQ1DgALIuYyMRh4j7fBA0mCfTKcwgANzyAAkEPh8BAcAB1Fj4TmZAD0KvVzJoIEEQA
Repro steps
Initialize
useRef
with some dummy value (e.g. null, Symbol, undefined, etc.) to be changed after initialization/during render.Update
ref.current
by checking whether it is equivalent to its initial condition (as per documentation: useRef#Avoiding recreating the ref contents)eslint-plugin-react-compiler gives error
How often does this bug happen?
Every time
What version of React are you using?
19.0.0-rc-1d989965-20240821