An open API service indexing awesome lists of open source software.

https://github.com/thetallprogrammer/redux-example

A small redux example I got from a youtube tutorial, I expanded on it by using typescript and created a diagram for better understanding.
https://github.com/thetallprogrammer/redux-example

Last synced: 3 months ago
JSON representation

A small redux example I got from a youtube tutorial, I expanded on it by using typescript and created a diagram for better understanding.

Awesome Lists containing this project

README

          

# Understanding Redux: A Comprehensive Guide

This documentation serves as a practical reference for Redux concepts, designed for future project use and to assist anyone seeking clarity on state management in JavaScript applications.

-----

## What is Redux?

**Redux** is a **predictable state container for JavaScript apps**, most commonly used with React. Imagine it as a **centralized warehouse** for all the data (the "state") your application needs. This makes it significantly easier to manage and access that data consistently from any component within your application.

![redux official diagram](/public/docs/ReduxDataFlowDiagram.gif)

### The Core Principle: Unidirectional Data Flow

At its heart, Redux operates on a simple, **one-way data flow**. This fundamental principle ensures predictability and makes debugging easier. The flow involves three main parts: the Store, Actions, and Reducers.

### 1\. The Store

The **Store** is a single, immutable JavaScript object that holds the entire state of your application. It's the **"single source of truth"** for your application's data. You'll only ever have one Redux store in your application.

### 2\. Actions

When you want to change the state, you can't modify it directly. Instead, you **dispatch an Action**. An action is a plain JavaScript object that **describes *what happened***. Think of it as sending a formal request or a "memo" to the store, indicating an intent to change the state.

**Example Action to add a movie:**

```json
{
"type": "movies/addMovie",
"payload": "Transformers"
}
```

### 3\. Reducers

A **Reducer** is a **pure function** that receives the current `state` and an `action`. Its sole responsibility is to decide how to update the state based on that action and return a **brand new state object**. It's called a "reducer" because it takes all incoming actions and "reduces" them down to a single new state. Crucially, reducers must never mutate the original state directly; they must always return a new copy.

-----

### The Redux Data Flow Cycle:

The entire process follows a clear cycle:

1. An event happens in your UI (e.g., a button click, an API response).
2. Your UI **dispatches an Action** describing the event.
3. The **Store** passes the current `state` and the `action` to a **Reducer**.
4. The **Reducer** computes and returns a **brand new state object**.
5. The **Store** updates itself with this new state.
6. Any UI components subscribed to the relevant parts of the state automatically **re-render** to reflect the changes.

This is better visualized in the official Redux data flow diagram:

-----

## The Example Project: Movie Management with Redux Toolkit

This project demonstrates a simple movie management application, originally derived from a tutorial ([YouTube Link](https://www.youtube.com/watch?v=QgK_-G-hWeA&t=1246s)). Its primary purpose is to illustrate **state management across multiple components**, where Redux (specifically Redux Toolkit) proves invaluable.

While the original tutorial utilized JavaScript, this implementation has been converted to **TypeScript** for enhanced type safety and adherence to modern industry standards. Additionally, the styling has been customized.

Here's a detailed, step-by-step breakdown of the data flow when a new movie is added:
![diagram](/public/docs/Redux%20Movie%20Example.png)

### The Movie Addition Process: Step-by-Step

#### 1\. User Interaction (in `MovieInput.jsx`)

* A user types a movie title, like "Transformers," into the `` field and clicks the "Add Movie" button.
* The button's `onClick={handleAddMovie}` event is triggered.
* Inside `handleAddMovie`, the `dispatch` function is called with the `addMovie()` action creator (from your slice). The current value of the input (`newMovie` state) is passed as the argument.
```javascript
// This function call initiates the Redux cycle
dispatch(addMovie("Transformers"));
```

#### 2\. The Action is Created and Dispatched
* The `addMovie("Transformers")` action creator generates a **plain JavaScript object**. Redux Toolkit automatically combines the `name` from your slice ("movies") with the reducer function name ("addMovie") to create the unique **action type**.
* The dispatched action object looks like this:
```json
{
"type": "movies/addMovie",
"payload": "Transformers"
}
```
* This action object is then sent to the Redux store via `dispatch`.

#### 3\. The Store and Root Reducer (in `store.js`)

* The store receives the action. Its primary role is to pass the current application `state` and the `action` to its main **"root reducer."**
* Your `configureStore` setup defines how different parts of your global state are managed. For instance, it specifies that the `movies` property in your global state is handled by `movieReducer`.
```javascript
reducer: {
movies: movieReducer, // <-- The store maps 'movies/...' actions to this reducer
},
```
* The store, through its root reducer, inspects the action type (`'movies/addMovie'`) and intelligently forwards it to the appropriate `movieReducer`.

#### 4\. The Slice Reducer Executes (in `movieSlice.js`)

* The `movieReducer` from your `movieSlice` takes over. It examines the `action.type` and executes the corresponding function defined in its `reducers` object.
* The `addMovie` function within `movieSlice` is executed:
* **`state`** here refers *only* to the current `movies` slice of the global state (e.g., `{ movies: [...] }`), not the entire app state.
* **`action`** is the action object from Step 2.

```javascript
addMovie: (state, action) => {
// action.payload is "Transformers"
const newMovie: Movie = {
id: state.movies[state.movies.length - 1].id + 1, // this state.movies
// is saying (state.movies).movies, state = (state.movies) in this scope
title: action.payload // The movie title from the action
}
// Redux Toolkit's Immer allows "mutating" logic,
// which safely produces an immutable new state.
state.movies.push(newMovie);
},
```
*(Note: The `id` generation has been updated to `Date.now()` for robust uniqueness, and `newMovie` is pushed instead of `action.payload` to ensure the correct object structure.)*

#### 5\. The State is Updated

* Redux Toolkit leverages a library called **Immer** behind the scenes. This powerful tool allows you to write state-updating logic that looks like it's directly "mutating" the state (e.g., `state.movies.push(...)`). Immer then safely translates these mutations into **immutable updates**, returning a brand new state object.
* The `movieSlice` returns a new state object specifically for the `movies` slice.
* The root reducer then assembles this new slice with any other (unchanged) slices to form the complete, new **global state object**.
* The store is now updated and holds this new, final application state.

#### 6\. The UI Re-Renders

* Any React components in your application that are **subscribed** to the Redux store (typically using the `useSelector` hook to extract data like the `movies` list) will be notified of the state change.
* `useSelector` efficiently compares the new data with the previously selected data. If the data has changed, the component will automatically **re-render** to display the updated information, ensuring your UI always reflects the latest state.

-----

## Getting Started

To explore this application and see Redux in action:

1. **Clone the repository** to your local machine.
2. Navigate to the project directory in your terminal.
3. Install dependencies: `npm install`
4. Start the development server: `npm run dev`

Feel free to experiment with and extend this project. Its core purpose is to inform and assist in understanding Redux, building upon the foundational concepts from the original tutorial.