Redux is a state management library used when application state becomes large or shared across many components.
The main idea is:
- state lives in a central store
- components read state through selectors
- components update state by dispatching actions
- reducers decide how the state changes
1) Redux basics
A reducer is a function that receives the current state and an action, then returns the next state.
const initialState = { counter: 0 };
const reducer = (prevState = initialState, action: { type: string; payload?: number }) => {
if (action.type === 'inc') {
return {
...prevState,
counter: prevState.counter + (action.payload ?? 1),
};
}
return prevState;
};
Important rule:
- never mutate the existing state object
- always return a new object
- keep all existing keys in the returned object unless you intentionally want to remove them
Creating the store
import { createStore } from 'redux';
const store = createStore(reducer);
Providing the store to React
import { Provider } from 'react-redux';
<Provider store={store}>
<App />
</Provider>
Reading and updating state in a component
import { useDispatch, useSelector } from 'react-redux';
function Counter() {
const counter = useSelector((state: { counter: number }) => state.counter);
const dispatch = useDispatch();
const increment = () => {
dispatch({ type: 'inc', payload: 5 });
};
return (
<>
<p>Counter: {counter}</p>
<button onClick={increment}>+5</button>
</>
);
}
useSelector reads data from the Redux store.
useDispatch sends an action to the reducer.
2) Redux Toolkit
Redux Toolkit is a simpler and more structured way to write Redux.
It gives us:
createSliceconfigureStore- simplified reducer logic
- automatic action creators
Example: counter slice
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: {
counter: 0,
show: false,
},
reducers: {
increment(state) {
state.counter += 1;
},
increase(state, action) {
state.counter += action.payload;
},
},
});
In Redux Toolkit, the reducer functions are written in a simpler style. We do not need a large switch statement, and we do not manually return the whole state object every time.
The state is still updated immutably under the hood by Immer, which is why we can mutate the draft state directly.
Configure the store
import { configureStore } from '@reduxjs/toolkit';
const store = configureStore({
reducer: {
counterReducer: counterSlice.reducer,
},
});
Export actions
export const counterActions = counterSlice.actions;
Use it in a component
import { useDispatch, useSelector } from 'react-redux';
import { counterActions } from './store';
function Counter() {
const counter = useSelector((state: any) => state.counterReducer.counter);
const dispatch = useDispatch();
return (
<>
<p>Counter: {counter}</p>
<button onClick={() => dispatch(counterActions.increment())}>+</button>
<button onClick={() => dispatch(counterActions.increase(5))}>+5</button>
</>
);
}
counterActions.increment() creates an action for the reducer, and counterActions.increase(5) sends a payload value.
3) Why Redux Toolkit is preferred
Redux Toolkit reduces boilerplate and makes Redux easier to work with.
It helps with:
- fewer manual action types
- less reducer boilerplate
- simpler state updates
- better organization for growing apps
4) Summary
- Redux stores data in one central store
- reducers handle state changes using actions
-
useSelectorreads state from the store -
useDispatchsends actions to update state - Redux Toolkit is the modern and easier way to use Redux
In practice, Redux Toolkit is usually the recommended choice for Redux-based apps because it keeps the same concepts but with much less code.
Top comments (0)