Search code examples
reactjsreact-hooksreact-lifecycle

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


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?


Solution

  • 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
    }