0

I am learning about custom hooks and useReducer in React.js. Here is an example (sandbox) to illustrate useReducer adapted from the course Modern React with Redux:

import "./styles.css";
import { useReducer } from "react";

const INCREMENT_COUNT = "increment";
const SET_VALUE_TO_ADD = "change_value_to_add";
const DECREMENT_COUNT = "decrement";
const ADD_VALUE_TO_COUNT = "add_value_to_count";

const reducer = (state, action) => {
  switch (action.type) {
    case INCREMENT_COUNT:
      return {
        ...state,
        count: state.count + 1
      };
    case DECREMENT_COUNT:
      return {
        ...state,
        count: state.count - 1
      };
    case ADD_VALUE_TO_COUNT:
      return {
        ...state,
        count: state.count + state.valueToAdd,
        valueToAdd: 0
      };
    case SET_VALUE_TO_ADD:
      return {
        ...state,
        valueToAdd: action.payload
      };
    default:
      return state;
  }
};

function CounterPage({ initialCount }) {
  const [state, dispatch] = useReducer(reducer, {
    count: initialCount,
    valueToAdd: 0
  });
  console.log(state);

  const increment = () => {
    dispatch({
      type: INCREMENT_COUNT
    });
  };
  const decrement = () => {
    dispatch({
      type: DECREMENT_COUNT
    });
  };
  const handleChange = (event) => {
    const value = parseInt(event.target.value) || 0;

    dispatch({
      type: SET_VALUE_TO_ADD,
      payload: value
    });
  };
  const handleSubmit = (event) => {
    event.preventDefault();

    dispatch({
      type: ADD_VALUE_TO_COUNT
    });
  };

  return (
    <>
      <h1>Count is {state.count}</h1>
      <div>
        <button onClick={increment}>Increment</button>&nbsp;
        <button onClick={decrement}>Decrement</button>
      </div>

      <form onSubmit={handleSubmit}>
        <label>Add a lot!</label>
        <input
          value={state.valueToAdd || ""}
          onChange={handleChange}
          type="number"
        />
        <button>Add it!</button>
      </form>
    </>
  );
}

export default function App() {
  return (
    <div className="App">
      <CounterPage initialCount={10} />
    </div>
  );
}

It seems to me that this example can be implemented simpler (sandbox) with a custom hook:

import { useState } from "react";
import "./styles.css";

const useCounter = (initialCount) => {
  const [count, setCount] = useState(initialCount);
  const [valueToAdd, setValueToAdd] = useState(0);

  const incrementCount = () => setCount(count + 1);
  const decrementCount = () => setCount(count - 1);
  const addValueToCount = () => setCount(count + valueToAdd);

  return {
    count,
    incrementCount,
    decrementCount,
    addValueToCount,
    valueToAdd,
    setValueToAdd
  };
};

function CounterPage({ initialCount }) {
  const state = useCounter(initialCount);

  const handleChange = (event) => {
    const value = parseInt(event.target.value) || 0;
    state.setValueToAdd(value);
  };

  const handleSubmit = (event) => {
    event.preventDefault();
    state.addValueToCount();
  };

  console.log("render");
  return (
    <>
      <h1>Count is {state.count}</h1>
      <div>
        <button onClick={state.incrementCount}>Increment</button>&nbsp;
        <button onClick={state.decrementCount}>Decrement</button>
      </div>

      <form onSubmit={handleSubmit}>
        <label>Add a lot!</label>
        <input
          value={state.valueToAdd || ""}
          onChange={handleChange}
          type="number"
        />
        <button>Add it!</button>
      </form>
    </>
  );
}

export default function App() {
  return (
    <div className="App">
      <CounterPage initialCount={10} />
    </div>
  );
}

I actually like how the custom hook organizes changing state into several functions instead of clumping everything into a single reducer. This reminds me of methods in OOP.

Why is useReducer preferable? If it's not preferable in this example, how can one modify the example to illustrate the benefits of using useReducer as opposed to using a custom hook?

AlwaysLearning
  • 7,257
  • 4
  • 33
  • 68
  • 1
    Who says it's preferable? Redux in general is best used for a specific set of things--if an app doesn't need those things using it rarely makes sense *(and custom hooks further reduce the sense)*. – Dave Newton Jun 06 '23 at 20:42
  • Who's saying useReducer is preferable? Seems like you're beginning with an assumption of a widespread opinion, and then asking for opinions of whether that opinion is correct. – Heretic Monkey Jun 06 '23 at 20:43
  • @HereticMonkey I am saying that it seems to me that useReducer is worse than custom hooks in every respect, so I don't understand why it exists and recommended by many. – AlwaysLearning Jun 06 '23 at 20:45
  • 1
    @DaveNewton The question does not mention Redux. It is about useReducer, which is part of React. – AlwaysLearning Jun 06 '23 at 20:48
  • @AlwaysLearning I mean except for the second sentence, sure--the same reasoning applies delta global vs independent/component state. Much of the same discussion from "You Might Not Need Redux" applies to `useReducer`. – Dave Newton Jun 06 '23 at 20:51

0 Answers0