If the useSelector()
hook is not an option on the table, the Redux connect
function can also map the Redux state to a function component.
Here is how I do it.
I will create a simple shopping cart with a counter to demonstrate the use of Redux's connect function.
Below are the steps to set up the store. The code with the connect
function is in the ShoppingCart component.
Simple actions to increment and decrement the shopping cart.
actions.tsx
export interface action { type: string, payLoad: number }
export const incrementCount = (inc: number) => {
return { type: "increment", payLoad: inc };
}
export const decrementCount = (dec: number) => {
return { type: "decrement", payLoad: dec };
}
Simple Reducer with a store to manage the state.
reducers.tsx
import { action } from './actions'
export interface shoppingCartState {
count: number
}
let initialState: shoppingCartState = { count: 0 };
export const shoppingCartReducer = (state = initialState, action: action) => {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + action.payLoad };
case 'decrement':
return { ...state, count: state.count - action.payLoad };
default:
return state;
}
}
Create the store with the reducers
store.tsx
import { configureStore } from '@reduxjs/toolkit';
import { shoppingCartReducer } from './reducers'
export const store = configureStore({ reducer: shoppingCartReducer });
A simple component to add and delete from the shopping cart.
This component uses hooks to dispatch actions that add and subtracts from the shopping cart.
content.tsx
import { useDispatch } from "react-redux"
import { incrementCount, decrementCount } from "../store/actions"
export const Content = () => {
const dispatch = useDispatch();
return (
<>
<p><button onClick={() => dispatch(incrementCount(1))}>Add 1 to cart</button></p>
<p><button onClick={() => dispatch(decrementCount(1))}>Delete 1 from cart</button></p>
</>
)
}
The Shopping cart uses the connect function.
In the ShoppingCart component, I use the connect
function to map the Redux state to my shopping cart component props.
shopping_cart.tsx
import { connect } from "react-redux"
import { shoppingCartState } from "../store/reducers"
interface ShoppingCartProps {
count: number
}
const ShoppingCart = (props: ShoppingCartProps) => {
return (
<p>Shopping cart : {props.count}</p>
)
}
const mapStateToProps = (state: shoppingCartState) => {
return {
count: state.count
}
}
export default connect(mapStateToProps)(ShoppingCart)
The connect
function calls the mapStateToProps()
function with the Redux state as the argument. The mapStateToProps()
returns the slice of the state that the ShoppingCart component needs. Then the connect
function calls the ShoppingCart component and passes the returned
value of the mapStateToProps()
as props to the ShoppingCart component.
The App.tsx puts the components together.
App.tsx
import { Content } from "./layout/content";
import ShoppingCart from "./layout/shopping_cart";
const App = () => {
return (
<div>
<ShoppingCart />
<Content />
</div>
);
}
export default App;
Finally, I wrap the pages with the Redux store to make the store available globally in the application.
index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import App from './App';
import { store } from './store/store';
ReactDOM.render(
<Provider store={store}>
<React.StrictMode>
<App />
</React.StrictMode>
</Provider>,
document.getElementById('root')
);