{"id":26811243,"url":"https://github.com/dev-emekaa/redux-e-com-guide","last_synced_at":"2026-04-20T03:05:37.020Z","repository":{"id":221538576,"uuid":"754669875","full_name":"dev-emekaa/Redux-E-com-Guide","owner":"dev-emekaa","description":"An E-commerce product page Template with React, Sass and Redux ToolKit. Easy to set up and understand. Can use as a starter file to configure your own product page with redux.","archived":false,"fork":false,"pushed_at":"2024-02-08T15:05:39.000Z","size":55,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-30T01:38:14.575Z","etag":null,"topics":["react","redux","redux-toolkit","sass"],"latest_commit_sha":null,"homepage":"","language":"SCSS","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dev-emekaa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2024-02-08T14:43:47.000Z","updated_at":"2024-04-22T21:39:58.000Z","dependencies_parsed_at":"2024-02-08T16:10:08.505Z","dependency_job_id":null,"html_url":"https://github.com/dev-emekaa/Redux-E-com-Guide","commit_stats":null,"previous_names":["techy-savant/redux-e-commerce-product-page-template","dev-hunterr/redux-e-com-guide","dev-emekaa/redux-e-com-guide"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dev-emekaa/Redux-E-com-Guide","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-emekaa%2FRedux-E-com-Guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-emekaa%2FRedux-E-com-Guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-emekaa%2FRedux-E-com-Guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-emekaa%2FRedux-E-com-Guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dev-emekaa","download_url":"https://codeload.github.com/dev-emekaa/Redux-E-com-Guide/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dev-emekaa%2FRedux-E-com-Guide/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32031070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-20T00:18:06.643Z","status":"online","status_checked_at":"2026-04-20T02:00:06.527Z","response_time":94,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["react","redux","redux-toolkit","sass"],"created_at":"2025-03-30T01:38:05.604Z","updated_at":"2026-04-20T03:05:36.973Z","avatar_url":"https://github.com/dev-emekaa.png","language":"SCSS","funding_links":[],"categories":[],"sub_categories":[],"readme":"# E-commerce Product Page Template with Redux Store and Redux ToolKit\n\n## Project Walkthrough\nThis project will give you a detailed guide to use redux toolkit. An alternative and better way to write Redux logic. It is perfect for someone new to redux, or someone looking for a template to speed up development time. The Readme is well detailed. Be sure to dive into it and the codebase.\n\n![ E-commerce Product Page Template with Redux Store and Redux ToolKit](https://github.com/techy-savant/Redux-E-commerce-Product-Page-Template/assets/108519575/99d25be9-2264-45b8-ac47-7491b2834e63)\n\n\n#### Docs\n\n[Redux Toolkit Docs](https://redux-toolkit.js.org/introduction/getting-started)\n\n#### Install Template\n\n```sh\nnpx create-react-app my-app --template redux\n```\n\n- @latest\n\n```sh\nnpx create-react-app@latest my-app --template redux\n```\n\n#### Existing App\n\n```sh\nnpm install @reduxjs/toolkit react-redux\n```\n\n#### @reduxjs/toolkit\n\nconsists of few libraries\n\n- redux (core library, state management)\n- immer (allows to mutate state)\n- redux-thunk (handles async actions)\n- reselect (simplifies reducer functions)\n\n#### Extras\n\n- redux devtools\n- combine reducers\n\n#### react-redux\n\nconnects our app to redux\n\n#### Setup Store\n\n- create store.js\n\n```js\nimport { configureStore } from \"@reduxjs/toolkit\";\n\nexport const store = configureStore({\n  reducer: {},\n});\n```\n\n#### Setup Provider\n\n- index.js\n\n```js\nimport React from \"react\";\nimport ReactDOM from \"react-dom\";\nimport \"./index.css\";\nimport App from \"./App\";\n// import store and provider\nimport { store } from \"./store\";\nimport { Provider } from \"react-redux\";\n\nReactDOM.render(\n  \u003cReact.StrictMode\u003e\n    \u003cProvider store={store}\u003e\n      \u003cApp /\u003e\n    \u003c/Provider\u003e\n  \u003c/React.StrictMode\u003e,\n  document.getElementById(\"root\")\n);\n```\n\n#### Setup Cart Slice\n\n- application feature\n- create features folder/cart\n- create cartSlice.js\n\n```js\nimport { createSlice } from \"@reduxjs/toolkit\";\n\nconst initialState = {\n  cartItems: [],\n  amount: 0,\n  total: 0,\n  isLoading: true,\n};\n\nconst cartSlice = createSlice({\n  name: \"cart\",\n  initialState,\n});\n\nconsole.log(cartSlice);\n\nexport default cartSlice.reducer;\n```\n\n- store.js\n\n```js\nimport { configureStore } from \"@reduxjs/toolkit\";\nimport cartReducer from \"./features/cart/cartSlice\";\n\nexport const store = configureStore({\n  reducer: {\n    cart: cartReducer,\n  },\n});\n```\n\n#### Redux DevTools\n\n- extension\n\n#### Access store value\n\n- create components/Navbar.js\n\n```js\nimport { CartIcon } from \"../icons\";\nimport { useSelector } from \"react-redux\";\n\nconst Navbar = () =\u003e {\n  const { amount } = useSelector((state) =\u003e state.cart);\n\n  return (\n    \u003cnav\u003e\n      \u003cdiv className=\"nav-center\"\u003e\n        \u003ch3\u003eredux toolkit\u003c/h3\u003e\n        \u003cdiv className=\"nav-container\"\u003e\n          \u003cCartIcon /\u003e\n          \u003cdiv className=\"amount-container\"\u003e\n            \u003cp className=\"total-amount\"\u003e{amount}\u003c/p\u003e\n          \u003c/div\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/nav\u003e\n  );\n};\nexport default Navbar;\n```\n\n#### Hero Icons\n\n- [Hero Icons](https://heroicons.com/)\n\n```css\nnav svg {\n  width: 40px;\n  color: var(--clr-white);\n}\n```\n\n#### Setup Cart\n\n- cartSlice.js\n\n```js\nimport cartItems from \"../../cartItems\";\n\nconst initialState = {\n  cartItems: cartItems,\n  amount: 0,\n  total: 0,\n  isLoading: true,\n};\n```\n\n- create CartContainer.js and CartItem.js\n- CartContainer.js\n\n```js\nimport React from \"react\";\nimport CartItem from \"./CartItem\";\nimport { useSelector } from \"react-redux\";\n\nconst CartContainer = () =\u003e {\n  const { cartItems, total, amount } = useSelector((state) =\u003e state.cart);\n\n  if (amount \u003c 1) {\n    return (\n      \u003csection className=\"cart\"\u003e\n        {/* cart header */}\n        \u003cheader\u003e\n          \u003ch2\u003eyour bag\u003c/h2\u003e\n          \u003ch4 className=\"empty-cart\"\u003eis currently empty\u003c/h4\u003e\n        \u003c/header\u003e\n      \u003c/section\u003e\n    );\n  }\n  return (\n    \u003csection className=\"cart\"\u003e\n      {/* cart header */}\n      \u003cheader\u003e\n        \u003ch2\u003eyour bag\u003c/h2\u003e\n      \u003c/header\u003e\n      {/* cart items */}\n      \u003cdiv\u003e\n        {cartItems.map((item) =\u003e {\n          return \u003cCartItem key={item.id} {...item} /\u003e;\n        })}\n      \u003c/div\u003e\n      {/* cart footer */}\n      \u003cfooter\u003e\n        \u003chr /\u003e\n        \u003cdiv className=\"cart-total\"\u003e\n          \u003ch4\u003e\n            total \u003cspan\u003e${total}\u003c/span\u003e\n          \u003c/h4\u003e\n        \u003c/div\u003e\n        \u003cbutton className=\"btn clear-btn\"\u003eclear cart\u003c/button\u003e\n      \u003c/footer\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default CartContainer;\n```\n\n- CartItem.js\n\n```js\nimport React from \"react\";\nimport { ChevronDown, ChevronUp } from \"../icons\";\n\nconst CartItem = ({ id, img, title, price, amount }) =\u003e {\n  return (\n    \u003carticle className=\"cart-item\"\u003e\n      \u003cimg src={img} alt={title} /\u003e\n      \u003cdiv\u003e\n        \u003ch4\u003e{title}\u003c/h4\u003e\n        \u003ch4 className=\"item-price\"\u003e${price}\u003c/h4\u003e\n        {/* remove button */}\n        \u003cbutton className=\"remove-btn\"\u003eremove\u003c/button\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        {/* increase amount */}\n        \u003cbutton className=\"amount-btn\"\u003e\n          \u003cChevronUp /\u003e\n        \u003c/button\u003e\n        {/* amount */}\n        \u003cp className=\"amount\"\u003e{amount}\u003c/p\u003e\n        {/* decrease amount */}\n        \u003cbutton className=\"amount-btn\"\u003e\n          \u003cChevronDown /\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/article\u003e\n  );\n};\n\nexport default CartItem;\n```\n\n#### First Reducer\n\n- cartSlice.js\n- Immer library\n\n```js\nconst cartSlice = createSlice({\n  name: \"cart\",\n  initialState,\n  reducers: {\n    clearCart: (state) =\u003e {\n      state.cartItems = [];\n    },\n  },\n});\n\nexport const { clearCart } = cartSlice.actions;\n```\n\n- create action\n\n```js\nconst ACTION_TYPE = \"ACTION_TYPE\";\n\nconst actionCreator = (payload) =\u003e {\n  return { type: ACTION_TYPE, payload: payload };\n};\n```\n\n- CartContainer.js\n\n```js\nimport React from \"react\";\nimport CartItem from \"./CartItem\";\nimport { useDispatch, useSelector } from \"react-redux\";\n\nconst CartContainer = () =\u003e {\n  const dispatch = useDispatch();\n\n  return (\n    \u003cbutton\n      className=\"btn clear-btn\"\n      onClick={() =\u003e {\n        dispatch(clearCart());\n      }}\n    \u003e\n      clear cart\n    \u003c/button\u003e\n  );\n};\n\nexport default CartContainer;\n```\n\n#### Remove, Increase, Decrease\n\n- cartSlice.js\n\n```js\nimport { createSlice } from \"@reduxjs/toolkit\";\nimport cartItems from \"../../cartItems\";\n\nconst initialState = {\n  cartItems: [],\n  amount: 0,\n  total: 0,\n  isLoading: true,\n};\n\nconst cartSlice = createSlice({\n  name: \"cart\",\n  initialState,\n  reducers: {\n    clearCart: (state) =\u003e {\n      state.cartItems = [];\n    },\n    removeItem: (state, action) =\u003e {\n      const itemId = action.payload;\n      state.cartItems = state.cartItems.filter((item) =\u003e item.id !== itemId);\n    },\n    increase: (state, { payload }) =\u003e {\n      const cartItem = state.cartItems.find((item) =\u003e item.id === payload.id);\n      cartItem.amount = cartItem.amount + 1;\n    },\n    decrease: (state, { payload }) =\u003e {\n      const cartItem = state.cartItems.find((item) =\u003e item.id === payload.id);\n      cartItem.amount = cartItem.amount - 1;\n    },\n    calculateTotals: (state) =\u003e {\n      let amount = 0;\n      let total = 0;\n      state.cartItems.forEach((item) =\u003e {\n        amount += item.amount;\n        total += item.amount * item.price;\n      });\n      state.amount = amount;\n      state.total = total;\n    },\n  },\n});\n\nexport const { clearCart, removeItem, increase, decrease, calculateTotals } =\n  cartSlice.actions;\n\nexport default cartSlice.reducer;\n```\n\n- CartItem.js\n\n```js\nimport React from \"react\";\nimport { ChevronDown, ChevronUp } from \"../icons\";\n\nimport { useDispatch } from \"react-redux\";\nimport { removeItem, increase, decrease } from \"../features/cart/cartSlice\";\n\nconst CartItem = ({ id, img, title, price, amount }) =\u003e {\n  const dispatch = useDispatch();\n\n  return (\n    \u003carticle className=\"cart-item\"\u003e\n      \u003cimg src={img} alt={title} /\u003e\n      \u003cdiv\u003e\n        \u003ch4\u003e{title}\u003c/h4\u003e\n        \u003ch4 className=\"item-price\"\u003e${price}\u003c/h4\u003e\n        {/* remove button */}\n        \u003cbutton\n          className=\"remove-btn\"\n          onClick={() =\u003e {\n            dispatch(removeItem(id));\n          }}\n        \u003e\n          remove\n        \u003c/button\u003e\n      \u003c/div\u003e\n      \u003cdiv\u003e\n        {/* increase amount */}\n        \u003cbutton\n          className=\"amount-btn\"\n          onClick={() =\u003e {\n            dispatch(increase({ id }));\n          }}\n        \u003e\n          \u003cChevronUp /\u003e\n        \u003c/button\u003e\n        {/* amount */}\n        \u003cp className=\"amount\"\u003e{amount}\u003c/p\u003e\n        {/* decrease amount */}\n        \u003cbutton\n          className=\"amount-btn\"\n          onClick={() =\u003e {\n            if (amount === 1) {\n              dispatch(removeItem(id));\n              return;\n            }\n            dispatch(decrease({ id }));\n          }}\n        \u003e\n          \u003cChevronDown /\u003e\n        \u003c/button\u003e\n      \u003c/div\u003e\n    \u003c/article\u003e\n  );\n};\n\nexport default CartItem;\n```\n\n- App.js\n\n```js\nimport { useEffect } from \"react\";\nimport Navbar from \"./components/Navbar\";\nimport CartContainer from \"./components/CartContainer\";\nimport { useSelector, useDispatch } from \"react-redux\";\nimport { calculateTotals } from \"./features/cart/cartSlice\";\n\nfunction App() {\n  const { cartItems } = useSelector((state) =\u003e state.cart);\n  const dispatch = useDispatch();\n  useEffect(() =\u003e {\n    dispatch(calculateTotals());\n  }, [cartItems]);\n\n  return (\n    \u003cmain\u003e\n      \u003cNavbar /\u003e\n      \u003cCartContainer /\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n\n#### Modal\n\n- create components/Modal.js\n\n```js\nconst Modal = () =\u003e {\n  return (\n    \u003caside className=\"modal-container\"\u003e\n      \u003cdiv className=\"modal\"\u003e\n        \u003ch4\u003eRemove all items from your shopping cart?\u003c/h4\u003e\n        \u003cdiv className=\"btn-container\"\u003e\n          \u003cbutton type=\"button\" className=\"btn confirm-btn\"\u003e\n            confirm\n          \u003c/button\u003e\n          \u003cbutton type=\"button\" className=\"btn clear-btn\"\u003e\n            cancel\n          \u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/aside\u003e\n  );\n};\nexport default Modal;\n```\n\n- App.js\n\n```js\nreturn (\n  \u003cmain\u003e\n    \u003cModal /\u003e\n    \u003cNavbar /\u003e\n    \u003cCartContainer /\u003e\n  \u003c/main\u003e\n);\n```\n\n#### modal slice\n\n- create features/modal/modalSlice.js\n\n```js\nimport { createSlice } from \"@reduxjs/toolkit\";\nconst initialState = {\n  isOpen: false,\n};\n\nconst modalSlice = createSlice({\n  name: \"modal\",\n  initialState,\n  reducers: {\n    openModal: (state, action) =\u003e {\n      state.isOpen = true;\n    },\n    closeModal: (state, action) =\u003e {\n      state.isOpen = false;\n    },\n  },\n});\n\nexport const { openModal, closeModal } = modalSlice.actions;\nexport default modalSlice.reducer;\n```\n\n- App.js\n\n```js\nconst { isOpen } = useSelector((state) =\u003e state.modal);\n\nreturn (\n  \u003cmain\u003e\n    {isOpen \u0026\u0026 \u003cModal /\u003e}\n    \u003cNavbar /\u003e\n    \u003cCartContainer /\u003e\n  \u003c/main\u003e\n);\n```\n\n#### toggle modal\n\n- CartContainer.js\n\n```js\nimport { openModal } from \"../features/modal/modalSlice\";\n\nreturn (\n  \u003cbutton\n    className=\"btn clear-btn\"\n    onClick={() =\u003e {\n      dispatch(openModal());\n    }}\n  \u003e\n    clear cart\n  \u003c/button\u003e\n);\n```\n\n- Modal.js\n\n```js\nimport { closeModal } from \"../features/modal/modalSlice\";\nimport { useDispatch } from \"react-redux\";\nimport { clearCart } from \"../features/cart/cartSlice\";\n\nconst Modal = () =\u003e {\n  const dispatch = useDispatch();\n\n  return (\n    \u003caside className=\"modal-container\"\u003e\n      \u003cdiv className=\"modal\"\u003e\n        \u003ch4\u003eRemove all items from your shopping cart?\u003c/h4\u003e\n        \u003cdiv className=\"btn-container\"\u003e\n          \u003cbutton\n            type=\"button\"\n            className=\"btn confirm-btn\"\n            onClick={() =\u003e {\n              dispatch(clearCart());\n              dispatch(closeModal());\n            }}\n          \u003e\n            confirm\n          \u003c/button\u003e\n          \u003cbutton\n            type=\"button\"\n            className=\"btn clear-btn\"\n            onClick={() =\u003e {\n              dispatch(closeModal());\n            }}\n          \u003e\n            cancel\n          \u003c/button\u003e\n        \u003c/div\u003e\n      \u003c/div\u003e\n    \u003c/aside\u003e\n  );\n};\nexport default Modal;\n```\n\n#### async functionality with createAsyncThunk\n\n- [Course API](https://course-api.com/)\n- https://course-api.com/react-useReducer-cart-project\n- cartSlice.js\n\n- action type\n- callback function\n- lifecycle actions\n\n```js\nimport { createSlice, createAsyncThunk } from \"@reduxjs/toolkit\";\n\nconst url = \"https://course-api.com/react-useReducer-cart-project\";\n\nexport const getCartItems = createAsyncThunk(\"cart/getCartItems\", () =\u003e {\n  return fetch(url)\n    .then((resp) =\u003e resp.json())\n    .catch((err) =\u003e console.log(error));\n});\n\nconst cartSlice = createSlice({\n  name: \"cart\",\n  initialState,\n  extraReducers: {\n    [getCartItems.pending]: (state) =\u003e {\n      state.isLoading = true;\n    },\n    [getCartItems.fulfilled]: (state, action) =\u003e {\n      console.log(action);\n      state.isLoading = false;\n      state.cartItems = action.payload;\n    },\n    [getCartItems.rejected]: (state) =\u003e {\n      state.isLoading = false;\n    },\n  },\n});\n```\n\n- App.js\n\n```js\nimport { calculateTotals, getCartItems } from \"./features/cart/cartSlice\";\n\nfunction App() {\n  const { cartItems, isLoading } = useSelector((state) =\u003e state.cart);\n\n  useEffect(() =\u003e {\n    dispatch(getCartItems());\n  }, []);\n\n  if (isLoading) {\n    return (\n      \u003cdiv className=\"loading\"\u003e\n        \u003ch1\u003eLoading...\u003c/h1\u003e\n      \u003c/div\u003e\n    );\n  }\n\n  return (\n    \u003cmain\u003e\n      {isOpen \u0026\u0026 \u003cModal /\u003e}\n      \u003cNavbar /\u003e\n      \u003cCartContainer /\u003e\n    \u003c/main\u003e\n  );\n}\n\nexport default App;\n```\n\n#### Options\n\n```sh\nnpm install axios\n```\n\n- cartSlice.js\n\n```js\nexport const getCartItems = createAsyncThunk(\n  \"cart/getCartItems\",\n  async (name, thunkAPI) =\u003e {\n    try {\n      // console.log(name);\n      // console.log(thunkAPI);\n      // console.log(thunkAPI.getState());\n      // thunkAPI.dispatch(openModal());\n      const resp = await axios(url);\n\n      return resp.data;\n    } catch (error) {\n      return thunkAPI.rejectWithValue(\"something went wrong\");\n    }\n  }\n);\n```\n\n#### The extraReducers \"builder callback\" notation\n\ncart/cartSlice\n\n```js\nconst cartSlice = createSlice({\n  name: \"cart\",\n  initialState,\n  reducers: {\n    // reducers\n  },\n  extraReducers: (builder) =\u003e {\n    builder\n      .addCase(getCartItems.pending, (state) =\u003e {\n        state.isLoading = true;\n      })\n      .addCase(getCartItems.fulfilled, (state, action) =\u003e {\n        // console.log(action);\n        state.isLoading = false;\n        state.cartItems = action.payload;\n      })\n      .addCase(getCartItems.rejected, (state, action) =\u003e {\n        console.log(action);\n        state.isLoading = false;\n      });\n  },\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-emekaa%2Fredux-e-com-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdev-emekaa%2Fredux-e-com-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdev-emekaa%2Fredux-e-com-guide/lists"}