2

If I have a component:

function MyComponent() {
  const state = useState(resetState())

  return jsx(state)
}

then I can trigger a state reset by passing a key to MyComponent:

<div>
  <MyComponent key={'resetStateOnChangingThisString'} />
</div>

If I want to refactor this component into a hook, what is the hooks equivalent of triggering a reset exactly when the key changes?

  • not using useEffect since it should reset before rendering
  • not using useMemo because that doesn't guarantee stability

I can use a combination of useMemo with a useRef to guarantee stability. Is this the best approach or am I missing something simpler?

skyboyer
  • 22,209
  • 7
  • 57
  • 64
bebbi
  • 2,489
  • 3
  • 22
  • 36

1 Answers1

0

This is the simplest approach I've found so far:

function useResetOnKeyChange(getInitialState, key) {
  const [state, setState] = useState(getInitialState);
  const keyRef = useRef();

  useMemo(() => {
    if (keyRef.current !== key) {
      keyRef.current = key;
      setState(getInitialState());
    }
  }, [key, getInitialState]);

  return state;
}

or a version without useState:

function useResetOnKeyChange<T>(
  getInitialState: () => T,
  key: string
) {
  const stateRef = useRef<T | undefined>()
  const keyRef = useRef<string | undefined>()

  const state = useMemo(() => {
    if (keyRef.current !== key) {
      keyRef.current = key
      stateRef.current = getInitialState()
    }

    return stateRef.current
  }, [key, getInitialState])

  return state
}
bebbi
  • 2,489
  • 3
  • 22
  • 36