Skip to content

Instantly share code, notes, and snippets.

@jschaf
Created October 29, 2021 22:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jschaf/6b2c802c27d44009be2128761c1c02c4 to your computer and use it in GitHub Desktop.
Save jschaf/6b2c802c27d44009be2128761c1c02c4 to your computer and use it in GitHub Desktop.
useStateRef hook
import type { Dispatch, SetStateAction } from 'react';
import { useCallback, useRef, useState } from 'react';
/** The returned value of a useRef hook, but marked as readonly. */
type ReadOnlyRef<T> = {
readonly current: T;
};
/** The return type of useStateRef. */
type StateRefResult<S> = [S, Dispatch<SetStateAction<S>>, ReadOnlyRef<S>];
/**
* A variant of useState that also returns a reference to the latest value.
* useState updates are batched, so re-renders may see stale values. If you need
* the latest value, use the last tuple element, the ReadOnlyRef to the latest
* state.
* https://stackoverflow.com/a/63039797/30900
*/
export function useStateRef<S = undefined>(): StateRefResult<S | undefined>;
export function useStateRef<S>(initialState: S): StateRefResult<S>;
export function useStateRef<S>(initialState?: S): StateRefResult<S> {
const [state, setState] = useState(initialState);
const ref = useRef(state);
const dispatch: Dispatch<SetStateAction<S>> = useCallback((setter) => {
ref.current = setter instanceof Function ? setter(ref.current as S) : setter;
setState(ref.current);
}, []);
return [state, dispatch, ref] as StateRefResult<S>;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment