Is there any significance to updating ref.current in an effect vs directly in render?

Viewed 164

I'm writing a utility hook to convert a variable to a react ref. This will not only establish the ref but update the current value and make the current value unassignable in the outer context (using TS).

export const useAsImmutableRef = <T>(value: T): Readonly<MutableRefObject<T>> => {
    const ref = useRef(value);
    useEffect(() => {
        ref.current = value;
    }, [value]);
    return ref;
};

When deciding how to update the current value I naturally went with the effect hook but I'm wondering if it could just be

export const useAsImmutableRef = <T>(value: T): Readonly<MutableRefObject<T>> => {
    const ref = useRef(value);
    ref.current = value;
    return ref;
};

To me it seems the latter would be better because at any point in time after the hooks usage it would be guaranteed the latest reference is being returned rather than delayed by a render via a useEffect usage. However it feels like bad practice as side effects in React should be in effect hooks. Is there a definite right vs wrong here?

1 Answers

This has been called the "latest ref pattern".

I believe the purpose of the useLayoutEffect (or useEffect) is because assigning to ref.current in the component body doesn't play nicely with server-side rendering or the upcoming suspense mode. React assumes that component bodies do not have side effects, and assigning a ref's value is a side effect that React isn't guaranteed to preserve.

Related