Initialization

Below, the state is initialized to init(initialCount). If the third argument to useReducer(), init, is omitted, the state will simply be initialized to initialCount.
RESETRUNFULL
<!DOCTYPE html><html>
  <head>
    <meta charset="UTF-8" />
    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
  </head>
  <body>
    <div></div>
    <script type="text/babel">
      function init(initialCount) {
        return {count: initialCount};
      }
      function reducer(state, action) {
        switch (action.type) {
          case 'increment':
            return {count: state.count + 1};
          case 'decrement':
            return {count: state.count - 1};
          case 'reset':
            return init(action.payload);
          default:
            throw new Error();
        }
      }
      function Counter({initialCount}) {
        const [state, dispatch] = React.useReducer(reducer, initialCount, init);
        return (<>
          Count: {state.count}
          <button onClick={() => dispatch({type: 'reset', payload: initialCount})}>
            Reset
          </button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
        </>);
      }
      const root = ReactDOM.createRoot(document.querySelector("div"));
      root.render(<Counter initialCount={0}/>);
    </script>
  </body></html>

As with useState(), if your reducer returns the same value (per Object.is comparison) as the current state, React will bail out of that update without re-rendering the component or firing effects. Hence, mutating state in place and then calling dispatch will not trigger a re-render.