1

I need help with adding types to a reducer function with optional dispatch. Here's the source of the pattern. https://twitter.com/FernandoTheRojo/status/1521312171262681090?s=20&t=oerzPqJ8cb5Ts3sHVMH_5Q

Here's the code:

[on, toggle] = useReducer(
  (prevState, next) => next == null ? !prevState : next, 
  false
)

And here is my attempt:

const [on, toggle] = useReducer(
  (prevState: boolean, next?: boolean) => (next == null ? !prevState : next),
  false
)

const enable = () => toggle(true) // Error Expected 0 arguments, but got 1.ts(2554)
const disable = () => toggle(false) // Error Expected 0 arguments, but got 1.ts
const toggleSwitch = () => toggle() // ☑️

And here's the codesandbox with a very similar example. https://codesandbox.io/s/usereducer-patterns-6gvrgh?file=/src/reducerHooks/ToggleOrSet.tsx

Thank you.

Onat
  • 771
  • 1
  • 11
  • 17
  • this is exactly why you should be using `useState` for this type of logic. `useState` is a basic Hook for managing simple state transformation, and `useReducer` is an additional Hook for managing more complex state logic – Derek Pollard Sep 29 '22 at 18:35

1 Answers1

1

Using useReducer() (not preferred)

This is about as close as it gets to the example you posted with type safety:

import { Reducer, useReducer } from 'react';

export function Toggler() {
  const [on, toggle] = useReducer<Reducer<boolean, boolean | undefined>>(
    (prevState: boolean, action?: boolean) => (action === undefined ? !prevState : action),
    false,
  );

  const enable = () => toggle(true);
  const disable = () => toggle(false);
  const toggleSwitch = () => toggle(undefined);
}

Again, I want to re-iterate that this is exactly why you should be using useState for this type of logic. useState is a basic Hook for managing simple state transformation, and useReducer is an additional Hook for managing more complex state logic

Using useState() (preferred)

import { useState } from 'react';

export function Toggler() {
  const [on, setOn] = useState(false);
  const enable = () => setOn(true);
  const disable = () => setOn(false);
  const toggle = () => setOn(currentOn => !currentOn);
}

The useState implementation is cleaner, easier to read and even smaller!

Derek Pollard
  • 6,953
  • 6
  • 39
  • 59