Redux, a key part of managing state in React apps, can seem daunting at first. But there’s a simpler way to approach it. In this blog, I’ll share my journey of understanding Redux and using it in a straightforward manner. I’ll show you how to easily add features like a shopping cart to your React app with Redux. Let’s explore Redux together and make state management in React simpler.
Setting Up Your Environment
Before diving into the code, make sure you have Node.js and npm (or yarn) installed on your machine. Create a new React application using Vite:
Next, install Redux Toolkit:
Creating the Redux Store
First, let’s create a Redux store to manage our application state. Inside the src directory, create a new folder called “store” and inside it, create a file named “store.js”:
import cartReducer from “./cartSlice”;
export const store = configureStore({
reducer: {
reducer: cartReducer,
},
});
export default store;
Defining the Cart Slice
Now, let’s define our cart slice, which includes the reducer and action creators. Create a new file named “cartSlice.js” in the “redux” folder:
const initialState = { itemList: [], totalQuantity: 0, showCart: false };
const cartSlice = createSlice({
name: “cart”,
initialState,
reducers: {
addToCart(state, action) {
const newItem = action.payload;
const existingItem = state.itemList.find(
(item) => item.id === newItem.id
);
if (existingItem) {
existingItem.quantity++;
existingItem.totalPrice = existingItem.price * existingItem.quantity;
} else {
state.itemList.push({
name: action.payload.name,
price: action.payload.price,
totalPrice: action.payload.totalPrice,
id: action.payload.id,
quantity: 1,
});
}
},
removeFromCart(state, action) {
const findItem = state.itemList.find(
(item) => item.id === action.payload.id
);
if (findItem.quantity === 1) {
state.itemList = state.itemList.filter(
(item) => item.id != action.payload.id
);
} else {
findItem.quantity–;
findItem.totalPrice -= findItem.price;
}
},
setShowCart(state) {
state.showCart = !state.showCart;
},
},
});
export const { addToCart, removeFromCart, setShowCart } = cartSlice.actions;
export default cartSlice.reducer;
This completes the redux setup now data insertion and fetch can be done using useDispatch and useSelector respectively. Here’s the way:
This is how you can add item to cart:
import { useDispatch, useSelector } from “react-redux”;
import { addToCart } from “./store/cartSlice”;
const ParticularItem = ({ name, id, price, desc }) => {
const dispatch = useDispatch();
const addCart = () => {
dispatch(addToCart({ name, id, price, desc, totalPrice: price }));
};
return (
<div>
<h1>{name}</h1>
<h1>{price}</h1>
<h1>{desc}</h1>
<button onClick={addCart} className=”adder”>
Add to Cart
</button>
</div>
);
};
export default ParticularItem;
This is how you can show the elements in cart:
import { useDispatch, useSelector } from “react-redux”;
import IndividualAdded from “./IndividualAdded”;
const AddedElements = () => {
const elements = useSelector((state) => state.reducer.itemList);
if (elements.length > 0) {
return (
<>
<ul>
{elements.map((item) => (
<li key={item.id}>
<IndividualAdded
name={item.name}
price={item.price}
quantity={item.quantity}
totalPrice={item.totalPrice}
id={item.id}
/>
</li>
))}
</ul>
</>
);
} else {
return <h1>Cart is empty</h1>;
}
};
export default AddedElements;
Other files:
App.jsx
import Items from “./Items”;
import Header from “./Header”;
import AddedElements from “./AddedElements”;
import { useSelector } from “react-redux”;
const App = () => {
const checkState = useSelector((state) => state.reducer.showCart);
return (
<>
<Header />
<Items />
{checkState && <AddedElements />}
</>
);
};
export default App;
Header.jsx
import { useSelector, useDispatch } from “react-redux”;
import { setShowCart } from “./store/cartSlice”;
const Header = () => {
const dispatch = useDispatch();
const elements = useSelector((state) => state.reducer.itemList);
const state = useSelector((state) => state.reducer.showCart);
const showElements = () => {
dispatch(setShowCart(state));
};
return (
<>
<header>
<h1>WELCOME</h1>
<button onClick={showElements}>Cart: {elements.length}</button>
</header>
</>
);
};
export default Header;
IndividualAdded.jsx
import { useDispatch } from “react-redux”;
import { addToCart, removeFromCart } from “./store/cartSlice”;
const IndividualAdded = ({ name, price, quantity, totalPrice, id }) => {
const dispatch = useDispatch();
const increment = () => {
dispatch(addToCart({ name, price, id }));
};
const decrement = () => {
dispatch(removeFromCart({ id, quantity, totalPrice, price }));
};
return (
<div className=”container2″>
<div className=”card”>
<h3 className=”first”>{name}</h3>
<h3 className=”second”>{price}</h3>
<h3 className=”third”>{quantity}</h3>
<h3 className=”forth”>{totalPrice}</h3>
<button onClick={increment}>+</button>
<button onClick={decrement}>-</button>
</div>
</div>
);
};
export default IndividualAdded;
Items.jsx
import ParticularItem from “./ParticularItem”;
import “./styles/items.scss”;
const Items = () => {
const items = [
{ name: “Laptop”, price: 123, desc: “new laptop”, id: 1 },
{ name: “Shoes”, price: 12, desc: “new shoe”, id: 2 },
];
return (
<>
<div className=”container”>
<ul>
{items.map((item) => (
<li key={item.price}>
<ParticularItem
name={item.name}
price={item.price}
desc={item.desc}
id={item.id}
/>
</li>
))}
</ul>
</div>
</>
);
};
export default Items;
and lastly main.jsx
import ReactDOM from “react-dom/client”;
import App from “./App.jsx”;
import { Provider } from “react-redux”;
import { store } from “./store/store.js”;
ReactDOM.createRoot(document.getElementById(“root”)).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
*Styling is totally upto you this is just the implementation
items.scss
margin: 0;
padding: 0;
box-sizing: border-box;
}
.container {
padding: 2rem 0 0 0;
width: 100vw;
ul {
display: flex;
justify-content: space-evenly;
list-style: none;
}
}
header {
display: flex;
justify-content: space-between;
padding: 2rem 10rem 0 10rem;
button {
font-size: 1.25rem;
padding: 2rem;
cursor: pointer;
}
}
.adder {
font-size: 1.25rem;
padding: 2rem;
cursor: pointer;
}
.card {
display: flex;
justify-content: space-evenly;
}