Flux Architecture (Redux)
Flux is an application architecture for building client-side web applications. It utilizes a unidirectional data flow. It is more of a pattern than a formal framework, though Redux is the most famous library implementing this pattern.
1. The Problem with MVC
In complex MVC applications, data flow can become bidirectional and chaotic.
- Models update Views.
- Views update Models.
- Models update other Models.
- Result: Cascading updates that are hard to debug.
2. The Solution: Unidirectional Data Flow
Flux enforces that data flows in a single direction. This makes the state of the application predictable.
The Flow
- Action: A user interaction (click) triggers an Action.
- Dispatcher: The Action is sent to the Dispatcher.
- Store: The Dispatcher updates the Store.
- View: The Store emits a change event, and the View re-renders.
3. Core Components
Actions
Simple objects describing what happened.
- Example:
{ type: 'ADD_TODO', text: 'Buy milk' }
Dispatcher
The central hub that manages all data flow. It receives actions and broadcasts them to registered stores. (In Redux, this is baked into the store).
Stores
Contain the application state and logic.
- Unlike MVC Models, a Store manages the state for a specific domain (e.g.,
UserStore,TodoStore). - Stores register with the Dispatcher.
Views (Controller Views)
React components that listen to change events from the Stores and re-render themselves.
4. Redux: The Evolution of Flux
Redux is a predictable state container for JavaScript apps. It simplifies Flux by:
- Single Source of Truth: Only one store for the entire app.
- State is Read-Only: The only way to change the state is to emit an action.
- Changes are made with Pure Functions (Reducers): Instead of multiple Stores updating themselves, you write Reducers that take the previous state and an action and return the next state.
// Reducer
function todoReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, { text: action.text, completed: false }];
default:
return state;
}
}
5. Flux vs. MVC
| Feature | MVC | Flux/Redux |
|---|---|---|
| Data Flow | Bidirectional (often) | Unidirectional (Strict) |
| State | Scattered across Models | Centralized (in Redux) |
| Logic | In Controllers/Models | In Stores/Reducers |
| Debuggability | Hard (Cascading updates) | Easy (Time travel debugging) |
6. Redux Middleware
Redux middleware provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. It is primarily used for logging, crash reporting, talking to an asynchronous API, routing, and more.
Redux Thunk
The standard way to define async action creators.
- Concept: Instead of returning an action object, an action creator returns a function (a thunk). This function receives
dispatchandgetStateas arguments. - Use Case: Simple async logic (e.g., fetching data).
// Thunk Action Creator
const fetchUser = (id) => async (dispatch) => {
dispatch({ type: 'FETCH_USER_START' });
try {
const response = await api.getUser(id);
dispatch({ type: 'FETCH_USER_SUCCESS', payload: response.data });
} catch (error) {
dispatch({ type: 'FETCH_USER_FAILURE', error });
}
};
Redux Saga
A library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like accessing the browser cache) easier to manage.
- Concept: Uses ES6 Generators (
function*) to make async code look synchronous and testable. - Use Case: Complex async flows (e.g., race conditions, cancelling requests, retries).
7. State Management Patterns
While Redux (Flux) is powerful, other patterns have emerged to solve state management in different ways.
Context API (React)
Built into React, it allows you to share values like these between components without having to explicitly pass a prop through every level of the tree.
- Best for: Low-frequency updates (Theme, User Language, Auth State).
- Drawback: Can cause unnecessary re-renders if not optimized carefully.
Recoil / Jotai (Atomic State)
These libraries introduce the concept of Atoms (units of state) and Selectors (derived state).
- Concept: Components subscribe to specific atoms. When an atom changes, only the components subscribed to that atom re-render.
- Best for: High-performance apps with complex, interdependent state (like a graphics editor).
programming/model-view-controller programming/client-vs-backend programming/functional-programming