Riad Kilani
  • Bio
  • Portfolio
  • Blog
  • Contact
  • Accessibility
  • Case Studies
  • CSS
  • Design
  • Front-End
  • HTML
  • JavaScript
  • News
  • Productivity
  • Random Thoughts
  • SEO
  • Themes
  • Trends
  • Tutorials
  • TypeScript
  • TypeSCript From The Ground Up
  • UX Engineering
  • Web Development
  • Wordpress
Home » Front-End » JavaScript Reducers: What They Are and Why Use Them

JavaScript Reducers: What They Are and Why Use Them

August 30, 2025
Light abstract background with faded JavaScript code, several green monopoly-style houses and one red hotel, and the title “JavaScript Reducers — What Are They and Why Use Them.”

TL;DR: A reducer is a tiny pure function that folds many things into one. Use reduce() to transform arrays (sum, group, map→object), and use state reducers (e.g., React’s useReducer) when your UI state transitions need clearer rules. Reducers make code predictable, testable, and easy to reason about.

Table of contents

  • The human-friendly definition
  • Why bother with reducers?
  • Array.prototype.reduce()—the pocket guide
  • Real problems, tiny reducers
  • State reducers (React & friends)
  • Best practices
  • Common gotchas
  • Keep learning
  • FAQ

The human-friendly definition

Think of a reducer like packing a suitcase: you start with an empty bag (accumulator), pick up one item at a time (current value), decide where it goes, zip the bag, and move on. At the end, you have one neatly packed suitcase.

// (accumulator, current) -> nextAccumulator
const sum = (acc, n) => acc + n;

const total = [2, 5, 7].reduce(sum, 0); // 14

You’ll meet reducers in two places: (1) array reducers with Array.prototype.reduce() and (2) state reducers (React useReducer, Redux) that turn (state, action) into next state.

Why bother with reducers?

  • Clarity: Many steps → one pass → one final thing.
  • Predictability: Pure functions (no hidden side effects) are easier to test.
  • Flexibility: The “one final thing” can be a number, object, Map, Set—whatever you need.
  • Great with TypeScript: Lock in the shape of your accumulator and stop guessing.

Array.prototype.reduce()—the pocket guide

array.reduce((accumulator, currentValue, index, array) => {
  // return next accumulator
}, initialValue);

Pro tips: Always provide an initialValue (your future self and empty arrays will thank you), and remember the accumulator can be any type or shape.

MDN: Array.prototype.reduce()

Real problems, tiny reducers

1) Quick math: sum + max

const nums = [4, 10, 6];

const total = nums.reduce((acc, n) => acc + n, 0);
const max   = nums.reduce((acc, n) => Math.max(acc, n), -Infinity);

2) Build a lookup map (id → object)

const users = [{ id:1, name:'A' }, { id:2, name:'B' }];

const byId = users.reduce((acc, u) => {
  acc[u.id] = u;
  return acc;
}, {});

// byId[2] -> { id:2, name:'B' }

3) Group items (e.g., by category)

const groupBy = (arr, key) =>
  arr.reduce((acc, item) => {
    const k = item[key];
    (acc[k] ??= []).push(item);
    return acc;
  }, {});

4) De-duplicate while preserving order

const unique = arr =>
  arr.reduce((acc, x) => (acc.includes(x) ? acc : acc.concat(x)), []);

5) Filter + map + total in one pass

const totalAfterDiscount = items.reduce((acc, item) => {
  if (!item.enabled) return acc;            // filter
  return acc + item.price * 0.9;            // map + reduce
}, 0);

New to fundamentals like scope and closures? Start here: Understanding JavaScript Scope. Async flows pair nicely with reducers: JavaScript Promise Basics.

State reducers (React & friends): same idea, bigger payoff

A state reducer still takes two inputs and returns one output—but now it’s (state, action) → nextState. That’s it.

const initial = { count: 0 };

function counter(state = initial, action) {
  switch (action.type) {
    case 'inc': return { ...state, count: state.count + 1 };
    case 'dec': return { ...state, count: state.count - 1 };
    default:    return state;
  }
}

React’s useReducer in practice

import { useReducer } from 'react';

function counter(state, action) {
  switch (action.type) {
    case 'inc': return { ...state, count: state.count + 1 };
    case 'dec': return { ...state, count: state.count - 1 };
    default:    return state;
  }
}

export default function Counter() {
  const [state, dispatch] = useReducer(counter, { count: 0 });
  return (
    <div>
      <button onClick={() => dispatch({ type: 'dec' })}>–</button>
      <span>{state.count}</span>
      <button onClick={() => dispatch({ type: 'inc' })}>+</button>
    </div>
  );
}

When to reach for useReducer over useState? Use it when multiple related fields change together, you want explicit transitions (e.g., idle → loading → success/error), or you need undo/redo.

Docs: React — useReducer • Redux — Structuring Reducers

Best practices (that save headaches)

  • Keep it pure: No fetching, no DOM—just inputs → output.
  • Set initialValue: Especially for array reducers.
  • Split big reducers: Small, focused reducers are easier to test and reuse.
  • Immutability helpers: Try Immer for concise updates.
  • Type it (TS): Declare accumulator/state shapes to catch errors early.
type Cart = { items: { id: string; qty: number }[] };

const add = (cart: Cart, id: string): Cart => ({
  ...cart,
  items: cart.items.some(i => i.id === id)
    ? cart.items.map(i => i.id === id ? { ...i, qty: i.qty + 1 } : i)
    : cart.items.concat({ id, qty: 1 })
});

Common gotchas

  • Forgetting initialValue and getting weird edge cases with empty arrays.
  • Returning the wrong type mid-reduce (start as a number, return an object later).
  • Mutating the accumulator when you intended immutability—be consistent.
  • Turning the reducer into a kitchen sink—split into helpers and compose.

Keep learning (internal + external links)

  • On my blog: Understanding JavaScript Scope • JavaScript Promise Basics • Evolution of Front-End Development (2010–2025)
  • Authoritative: MDN: reduce() • React docs: useReducer • Redux: Structuring Reducers • Immer

FAQ

Are reducers faster than multiple loops?
Not automatically. Reducers are about clarity and composition, not guaranteed speed. Profile if performance matters.

Should I always use reducers for state?
No. For simple UI, useState is great. Use a reducer when transitions are complex or you need predictable updates.

Is reduce() the same as a Redux reducer?
They share the fold idea (many → one). reduce() folds array items; Redux/React reducers fold actions into state.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

← Previous Post Up and Running with Vue.js (Fast Start for 2025)
Next Post → First Graphic Design Résumé: Rediscovering My Creative Journey

Categories

  • Accessibility
  • Case Studies
  • CSS
  • Design
  • Front-End
  • HTML
  • JavaScript
  • News
  • Productivity
  • Random Thoughts
  • SEO
  • Themes
  • Trends
  • Tutorials
  • TypeScript
  • TypeSCript From The Ground Up
  • UX Engineering
  • Web Development
  • Wordpress

Recent Posts

  • Native CSS Is Quietly Replacing Sass, But It Isn’t Replacing the “Need” for Sass
  • Everyday Types Explained (From the Ground Up)
  • 2026 CSS Features You Must Know (Shipped Late 2025–Now)
  • 60 JavaScript Projects in 60 Days
  • JavaScript vs TypeScript: What Actually Changes

Tags

accessibility accessible web design ADA compliance async components Career Journey cascade layers code splitting composables composition api computed properties container queries css Design Inspiration Design Systems disability access File Organization Front-End Development Frontend frontend development immutability javascript JavaScript reducers lazy loading Material Design Modern CSS performance Personal Growth react React useReducer Redux Resume screen readers seo Suspense Teleport TypeScript UI/UX UI Engineering UX UX Engineering Vue Router WCAG web accessibility Web Development Web Performance

Riad Kilani Front-End Developer

© 2026 Riad Kilani. All rights reserved.