šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
HTML MASTER CLASS /// LEARN TAGS /// BUILD STRUCTURE /// SEMANTIC WEB /// HTML MASTER CLASS /// LEARN TAGS ///

Redux Core in React: Web Development

Learn to design robust action structures, implement pure reducer logic, and manage the unidirectional data flow that defines professional React apps.

⚔ Total XP: 0|šŸ’» react XP: 0

Skill Matrix

UNLOCK NODES BY LEARNING NEW TAGS.

System Hub

Core logic.

Quick Quiz //

What is the primary danger of ignoring this concept?


šŸš€ LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
šŸŽ“ COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.

Redux centralizes your application's state into a single Store, updated only through dispatched actions and pure reducer functions. This lesson covers the core Redux API — createStore, actions, action creators, and reducers — before wiring any of it into React.

1The Redux Core

The Redux core library centers on a single object called the Store — think of it as one giant, tightly protected global variable that holds your entire application's state. Rather than scattering state across many components, Redux consolidates it into this one place.

The Store exposes exactly three core operations you'll use constantly: createStore() to set it up, dispatch() to send it actions describing what happened, and getState() to read its current data.

āœ•
—
+
// Example
console.log("Running React...");
localhost:3000

Redux Core API

2Creating the Store

Every Redux application begins by calling createStore(), imported from the redux package. You must pass your root reducer function into createStore as its argument — const store = createStore(rootReducer) — so the Store knows exactly how to calculate a new state whenever it receives a future action.

Without a reducer, the Store has no logic to fall back on; the reducer is what defines how every possible action transforms the current state into the next one.

āœ•
—
+
import { createStore } from 'redux';
const store = createStore(myReducer);
localhost:3000
STORE = createStore(REDUCER)

3Actions (The WHAT)

Once a Store exists, you interact with it through Actions — plain JavaScript objects that describe what happened, such as { type: 'USER_LOGIN_SUCCESS' }. The only requirement Redux strictly enforces is that every action object must include a type property, conventionally an uppercase string with underscores.

Actions don't perform any logic themselves; they're just descriptive messages that get sent to the reducer, which decides how to respond to them.

āœ•
—
+
const action = {
  type: 'ADD_TODO',
  payload: 'Learn Redux'
};
localhost:3000

Action Signatures

4Action Payloads

Actions often need to carry data along with the type, such as the text a user typed or the id of an item being added. By convention, that extra data goes inside a property named payload, e.g. { type: 'ADD_ITEM', payload: { id: 1, name: 'Apple' } }.

Redux itself doesn't require a payload field — only type is mandatory — but using payload consistently is the universal community standard that keeps action shapes predictable across a codebase.

āœ•
—
+
function addTodo(text) {
  return {
    type: 'ADD_TODO',
    payload: text
  };
}
localhost:3000

Data Payloads

5Action Creators

Hardcoding action objects directly inside UI components is risky — a single typo in the type string, like 'ADD_ITM' instead of 'ADD_ITEM', causes a silent failure with no error thrown. Action creators solve this: an action creator is just a plain JavaScript function that returns a correctly-shaped action object, e.g. function addItem(item) { return { type: 'ADD_ITEM', payload: item }; }.

Calling dispatch(addItem(item)) instead of hand-writing the object everywhere centralizes the action's shape in one place, so a typo only needs fixing once.

āœ•
—
+
function reducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    default:
      return state;
  }
}
localhost:3000

Typo Prevention

Wrap objects in functions.

6Reducers (The HOW)

The reducer is the brain of the Store — a plain function that takes two parameters, the current state and the action that was dispatched, and returns a new value that becomes the next state. On Redux's very first run, state is undefined, which is why reducers always declare a default parameter, like function reducer(state = initialState, action) { ... }.

That default is what seeds the Store with its starting values before any action has ever been dispatched.

āœ•
—
+
// Bad āŒ: state.val = 1;
// Good āœ…: return { ...state, val: 1 };
localhost:3000
Reducer(State, Action) => State

7Switch Statements

A single reducer often has to handle dozens of distinct action types, like 'LOGIN', 'LOGOUT', or 'UPDATE_PROFILE', and chaining if/else blocks for all of them quickly turns unreadable. The industry-standard pattern instead uses a JavaScript switch statement on action.type, with one case per action and a mandatory default: return state; fallback.

That default case matters — if a reducer doesn't recognize the incoming action type, it must still return the existing state unchanged, never undefined or null.

āœ•
—
+
store.dispatch({ type: 'INCREMENT' });
console.log(store.getState());
localhost:3000

Switch Statements

8The Immutability Rule

Reducers must be pure functions, which means they can never mutate the state object directly — writing state.score = state.score + 10; return state; breaks Redux's ability to detect that anything changed. Instead, you use the spread operator (...) to copy every existing property into a brand-new object and then overwrite just the properties that changed: return { ...state, score: state.score + 10 };.

Returning a new object reference is exactly what lets Redux, and React-Redux, efficiently detect that the state actually changed.

āœ•
—
+
<h1>Redux Core Master Unlocked!</h1>
localhost:3000

Immutability šŸ”’

{ ...state, changed: new }

9Step-by-Step Breakdown

The Redux Core. Welcome to the Redux Core. Now that we understand the philosophy, let's look at the actual code. To implement Redux, we use the core redux library. The central piece of the architecture is the 'Store'. It acts like a giant, highly protected global variable that holds your entire application state.

Creating the Store. The first step in any Redux application is to create the Store using createStore(). You must pass your root reducer function into createStore as its primary argument, so the Store knows how to handle future actions and calculate new states.

Actions (The WHAT). Once the store exists, you interact with it via Actions. As we covered, an Action is a plain JS object describing WHAT happened. The only strict requirement enforced by Redux is that the object MUST have a type property (typically a string in uppercase with underscores).

Action Payloads. Actions usually need to carry data to the Reducer. If the user typed a message, the action must carry that text string. By convention, we put this extra data inside a property named payload. This isn't technically required by the library, but it is the universal community standard.

Which property is STRICTLY REQUIRED by the Redux core library inside every Action object?

  • →data
  • →payload
  • →type

Action Creators. Hardcoding action objects throughout your UI components is dangerous because a simple typo in the type string will cause silent failures. To fix this, we use 'Action Creators'. An Action Creator is simply a JavaScript function that returns an action object.

Reducers (The HOW). The Reducer is the brain of the Store. It is a standard function that takes two parameters: state (the current data) and action (the event). It returns a new object that replaces the current state. The first time Redux runs, the state is undefined, so you must provide a default initial state parameter (e.g., state = 0).

Switch Statements. Because a reducer might need to handle dozens of different action types ('LOGIN', 'LOGOUT', 'UPDATE_PROFILE', etc.), using if/else blocks gets extremely messy. The industry standard is to use a JavaScript switch statement on action.type.

What must a Reducer ALWAYS return in its default switch case if it does not recognize the action.type?

  • →return null;
  • →return state;
  • →throw Error();

The Immutability Rule. As discussed in the intro, reducers MUST be pure functions. They cannot mutate state directly. You must use the spread operator (...) to copy the old state properties into a new object, and then overwrite the specific properties that changed.

Store Dispatch. To execute an action, we use store.dispatch(). You pass an action object (usually generated by an Action Creator) directly into this method. Redux immediately sends this action, along with the current state, into your Root Reducer. It evaluates the switch statement, returns the new state, and saves it in the Store.

Which function do we use to prevent typing errors by generating our Action objects automatically?

  • →Action Creators
  • →Reducers

Reading State. If you need to manually inspect the current state of the global store outside of a React component, you can call store.getState(). This returns the entire massive JavaScript object representing your application's current reality.

Unidirectional Flow. The reason we write all this boilerplate code is to enforce a strict, predictable 'Unidirectional Data Flow'. The UI triggers an Action Creator -> dispatch() sends the Action -> The Reducer calculates a new state -> The Store updates and notifies the UI. Data only ever flows in ONE direction.

Mastery Achieved. Fantastic! You've mastered the Redux Core API. You know how to create the Store, dispatch Actions via Action Creators, and write Pure Reducers using Switch statements. While you can use Redux entirely on its own, it's usually integrated directly into React components.

Level Up šŸš€

Advanced cheat sheets, SEO tricks, and interview prep for this topic.

Browser Support

ChromeSupported

Fully supported.

FirefoxSupported

Fully supported.

SafariSupported

Fully supported.

EdgeSupported

Fully supported.

Accessibility (A11y)

1Redux State Changes Should Still Trigger Accessible UI Updates

When a dispatched action changes state that affects visible feedback, like a form validation error or a loading status, make sure the connected component announces that change via an `aria-live` region — Redux itself has no awareness of accessibility, so the responsibility falls entirely on the connected UI layer.

2Keep Redux-Driven Focus Management Intentional

If dispatching an action causes a modal or route to open, move keyboard focus into the new content explicitly — a Store update that changes what's rendered doesn't automatically move focus for screen reader or keyboard users.

SEO Implications

  • 1

    Redux State Doesn't Exist Server-Side by Default

    A plain Redux store initialized with `createStore()` on the client starts fresh with its initial state during server-side rendering; any content computed from client-dispatched actions won't appear in the pre-hydration HTML a crawler sees unless the store is explicitly hydrated with server data.

  • 2

    Centralizing Content State in Redux Simplifies Consistent Rendering

    Keeping page content driven by a single, predictable Store makes it easier to guarantee the same data renders identically wherever it's displayed, reducing the risk of inconsistent or duplicate content across routes.

Best Practices

Always Provide a Default Parameter for the Reducer's State

Since Redux calls every reducer once with `state` as `undefined` to obtain the initial state, always write `function reducer(state = initialState, action)` — omitting the default causes the Store to start with undefined state.

Never Mutate State Inside a Reducer

Always build a new object or array with the spread operator, like `{ ...state, key: newValue }`, instead of assigning directly to a property on `state` — mutating in place means Redux and connected components can't detect that anything changed.

Frequent Bugs

THE BUG

A reducer's default case is missing, so dispatching an unrecognized action type causes the state to become undefined.

THE FIX

Always include a `default: return state;` case in the reducer's switch statement so unrecognized action types leave the existing state untouched.

THE BUG

A typo in an action's type string, such as 'ADD_ITM' instead of 'ADD_ITEM', causes the dispatch to silently do nothing.

THE FIX

Use action creator functions instead of hand-writing action objects inline — centralizing the type string in one function means a typo only needs to be fixed in a single place, and mismatches surface faster.

Real-World Examples

A Counter Reducer With Switch Statement and Default Case

A simple counter feature dispatches `{ type: 'INCREMENT' }` and `{ type: 'DECREMENT' }` actions, and the root reducer uses a switch statement to compute the next numeric state, always falling back to the current state for unrecognized actions.

function counterReducer(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1;
    case 'DECREMENT':
      return state - 1;
    default:
      return state;
  }
}

Interview Prep

?Frequently Asked Questions

Pascual Vila

Pascual Vila

Frontend Instructor // Code Syllabus

Common Pitfalls & Errors

The Error //

Mutating State Directly

// Wrong const [user, setUser] = useState({ name: 'Alice' }); user.name = 'Bob'; // React won't re-render // Correct setUser({ ...user, name: 'Bob' });

The Solution //

Never mutate a state variable directly (e.g., state.count = 1). Always use the setter function provided by useState to ensure the component re-renders.

The Error //

Missing 'key' prop in lists

// Wrong {items.map(item => <li>{item.name}</li>)} // Correct {items.map(item => <li key={item.id}>{item.name}</li>)}

The Solution //

When rendering a list of elements using .map(), always provide a unique 'key' prop to the outermost element to help React identify which items have changed.

Lesson Glossary

[01]Action Creator

A function that returns a formatted action object.

Code Preview
addTodo()

[02]Pure Function

A function that has no side effects and is predictable.

Code Preview
Reducers

[03]Immutability

The state of being unchangeable; creating copies instead of modifying.

Code Preview
Spread operator

[04]Switch Statement

Standard JS syntax used in reducers to handle action types.

Code Preview
switch(type)

[05]getState()

Store method used to retrieve the current state snapshot.

Code Preview
store.getState()

[06]Unidirectional Flow

The strict data path: UI -> Action -> Reducer -> Store.

Code Preview
One way

[07]Boilerplate

The code required to set up the Redux pattern.

Code Preview
Setup code

Continue Learning