Skip to main content

The Core Principles of Redux (Part 1): Single Source of Truth and State is Read-Only #105

?? Introduction

As React apps grow, state starts spreading everywhere: local component state, lifted state, context providers, and utility modules. That works for small features, but it gets stressful when multiple parts of the UI need the same data and can update it at different times. You click one button, another area changes unexpectedly, and debugging becomes a timeline puzzle.

That is the problem Redux was designed to solve. Redux is not �magic state,� and it is not tied to React internals. It is a simple architecture with strict rules that make change predictable.

In this lesson, we focus on the first two rules behind that predictability:

  1. The app has one single source of truth.
  2. The state is read-only from the UI�s perspective.

If you truly understand these two ideas, the rest of Redux (reducers, store setup, middleware, Redux Toolkit) becomes much easier.


?? Prerequisites

Before continuing, you should be comfortable with:

  • React component state and props.
  • Why immutable updates matter in React.
  • Basic JavaScript objects and arrays.

If needed, revisit Context API pitfalls first.


?? Article Outline: What You'll Master

By the end of this lesson, you will be able to:

  • Explain why Redux prefers one centralized state tree.
  • Describe why direct mutation from components is forbidden.
  • Model state and actions for a realistic React feature.
  • Understand how these two principles improve debugging, testing, and team collaboration.

?? Section 1: Single Source of Truth

Redux keeps the entire application state in one store object. Not �one store per feature,� not �one mutable object per page.� One canonical state tree.

A practical example:

{
auth: {
user: { id: 'u42', name: 'Mina' },
token: '...'
},
cart: {
items: [
{ id: 'p1', name: 'Mechanical Keyboard', quantity: 1, price: 99 },
{ id: 'p7', name: 'Mouse Pad', quantity: 2, price: 15 }
],
couponCode: null
},
ui: {
isCartOpen: false,
toast: null
}
}

Why this helps in React projects:

  • Consistency: every component reads from the same canonical data.
  • Traceability: state snapshots are easy to inspect in DevTools.
  • Refactoring safety: moving UI pieces around does not duplicate business state.
  • Server hydration and persistence: one object is simpler to save/restore.

This does not mean �put absolutely everything in Redux.� Ephemeral UI state (for example, a single uncontrolled input�s temporary text) can still stay local with useState. Redux is best for shared, long-lived, business-relevant state.


?? Section 2: State Is Read-Only

In Redux, components do not mutate state directly. They request a change by dispatching an action.

An action is just a plain object describing what happened:

{ type: 'cart/itemAdded', payload: { id: 'p1', quantity: 1 } }

This rule creates a clean flow:

  1. UI event happens (onClick, onSubmit, effect callback).
  2. Component dispatches an action.
  3. Reducer calculates next state from previous state + action.
  4. React re-renders with the updated snapshot.

Because every change is explicit, Redux DevTools can show a time-ordered history of actions and resulting state. That makes bugs reproducible instead of mysterious.

React example with hooks

import { useDispatch, useSelector } from 'react-redux';
import { addItem } from './cartSlice';

export default function ProductCard({ product }) {
const dispatch = useDispatch();
const quantity = useSelector(
state => state.cart.items.find(i => i.id === product.id)?.quantity ?? 0
);

return (
<article>
<h3>{product.name}</h3>
<p>${product.price}</p>
<button onClick={() => dispatch(addItem({ id: product.id }))}>
Add to cart ({quantity})
</button>
</article>
);
}

Notice what is not happening: no direct state.cart.items.push(...) inside the component. The component describes intent; reducers own transitions.


?? Section 3: Why These Principles Work Together

A single state tree without read-only discipline would still be fragile, because any component could mutate anything at any time.

Read-only updates without a shared source could still fragment truth across competing stores.

Together, they give you:

  • one place to inspect,
  • one legal way to request changes,
  • one deterministic mechanism to apply changes.

That combination is why Redux scales well in teams. New contributors can inspect state shape and action names and quickly understand system behavior.


?? Conclusion & Key Takeaways

Redux�s first two principles are less about syntax and more about architecture discipline. Keep one canonical state tree, and treat that state as read-only from the UI layer. Dispatch actions to describe events, then let reducers compute the next state.

Key takeaways:

  • A single source of truth reduces state drift across components.
  • Read-only state enforces explicit, traceable updates.
  • React hooks like useSelector and useDispatch fit naturally into this model.
  • These rules make debugging and testing substantially easier.

?? Next Steps

In The Core Principles of Redux (Part 2), we will cover the third principle: state transitions are handled by pure functions (reducers), and why purity is crucial for predictability.


glossary

  • Single Source of Truth: The entire app state lives in one store object.
  • Read-Only State: Components cannot mutate state directly; they dispatch actions.
  • Action: A plain object that describes an event that happened.
  • Dispatch: Sending an action to the store so reducers can process it.
  • Immutability: Creating new state values instead of mutating existing ones.

Further Reading