react hooks equivalent of passing a `key` to a component to control its lifecycle

85 Views Asked by At

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?

1

There are 1 best solutions below

0
bebbi On BEST ANSWER

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
}