{"id":26422765,"url":"https://github.com/tabotcharlesbessong/all-react-from-john-smilga","last_synced_at":"2025-03-18T02:26:30.192Z","repository":{"id":41467720,"uuid":"439769203","full_name":"TabotCharlesBessong/all-react-from-john-smilga","owner":"TabotCharlesBessong","description":"This repository includes all  what i have learned from John Smilga related to react he is one if not the best teacher on youtube and all over the internet ","archived":false,"fork":false,"pushed_at":"2023-02-09T10:36:56.000Z","size":18222,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2023-03-05T11:07:20.341Z","etag":null,"topics":["ax","raectjs","react","redux"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/TabotCharlesBessong.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}},"created_at":"2021-12-19T03:48:14.000Z","updated_at":"2023-03-02T19:34:28.000Z","dependencies_parsed_at":"2023-02-12T15:02:19.514Z","dependency_job_id":null,"html_url":"https://github.com/TabotCharlesBessong/all-react-from-john-smilga","commit_stats":null,"previous_names":[],"tags_count":null,"template":null,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TabotCharlesBessong%2Fall-react-from-john-smilga","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TabotCharlesBessong%2Fall-react-from-john-smilga/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TabotCharlesBessong%2Fall-react-from-john-smilga/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/TabotCharlesBessong%2Fall-react-from-john-smilga/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/TabotCharlesBessong","download_url":"https://codeload.github.com/TabotCharlesBessong/all-react-from-john-smilga/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244142787,"owners_count":20405081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["ax","raectjs","react","redux"],"created_at":"2025-03-18T02:26:29.565Z","updated_at":"2025-03-18T02:26:30.180Z","avatar_url":"https://github.com/TabotCharlesBessong.png","language":"JavaScript","funding_links":["https://www.buymeacoffee.com/johnsmilga"],"categories":[],"sub_categories":[],"readme":"\n\n#### All Projects\n\n[Projects Site](https://react-projects.netlify.app/)\n\n## Corresponding Tutorial Topics\n\n#### useState\n\n1. Birthday Reminder\n\n#### useEffect and Conditional Rendering\n\n2. Tours\n3. Reviews\n4. Questions\n5. Menu\n6. Tabs\n7. Slider\n\n#### Forms\n\n8. Lorem Ipsum Generator\n9. Color Shades Generator\n10. Grocery Bud\n\n#### useRef\n\n11. Navbar\n\n#### useContext\n\n12. Modal And Sidebar\n13. Stripe Submenus\n\n#### useReducer and useContext\n\n14. Cart\n\n#### React Router and useCallback\n\n15. Cocktails\n\n## Advanced Projects (Course Exclusive)\n\n[Course Link](https://www.udemy.com/course/react-tutorial-and-projects-course/?couponCode=REACT-OCT)\n\n16. Markdown Preview\n17. Random Person\n18. Pagination\n19. Stock Photos\n20. Dark Mode\n21. Movie DB\n22. Hacker News\n23. Quiz\n\n\naxios tutorial section\n\n# Axios Tutorial\n\n#### React Course\n\n[My React Course](https://www.udemy.com/course/react-tutorial-and-projects-course/?referralCode=FEE6A921AF07E2563CEF)\n\n\n\n#### Docs\n\n[Axios Docs](https://axios-http.com/docs/intro)\n\n#### Install\n\n```sh\nnpm install axios\n```\n\n```js\n\u003cscript src='https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'\u003e\u003c/script\u003e\n```\n\n#### First Request\n\n- import axios\n\n- axios.get(url)\n- axios.post(url)\n- axios.patch/put(url)\n- axios.delete(ulr)\n\n- default get axios(url)\n\n- returns a promise\n- response data located in data property\n- error in error.response\n\n```js\nimport axios from 'axios';\n\nconst fetchData = async () =\u003e {\n  try {\n    // axios.get(), axios.post(),axios.put(), axios.delete()\n    const response = await axios(url);\n\n    console.log(response);\n  } catch (error) {\n    console.log(error.response);\n  }\n};\n```\n\n#### Headers\n\n- second argument\n- axios.get(url,{})\n\n- third argument in requests with data\n- axios.post(url,{data},{})\n\n```js\nconst fetchDadJoke = async () =\u003e {\n  try {\n    const { data } = await axios(url, {\n      headers: {\n        Accept: 'application/json',\n      },\n    });\n    // console.log(data);\n    setJoke(data.joke);\n  } catch (error) {\n    console.log(error.response);\n  }\n};\n```\n\n#### Post Request\n\n- send data to the server\n- axios.post(url, { data })\n- more options (auth header) - axios.post(url, { data },{})\n\n```js\ntry {\n  const resp = await axios.post(url, { data });\n} catch (error) {\n  console.log(error.response.data);\n}\n```\n\n#### Global Defaults\n\n```js\naxios.defaults.headers.common['Accept'] = 'application/json';\naxios.defaults.baseURL = 'https://api.example.com';\naxios.defaults.headers.common['Authorization'] = AUTH_TOKEN;\naxios.defaults.headers.post['Content-Type'] =\n  'application/x-www-form-urlencoded';\n```\n\n#### Custom Instance\n\n```js\nconst authFetch = axios.create({\n  baseURL: 'https://course-api.com',\n  headers: {\n    Accept: 'application/json',\n  },\n});\n```\n\n#### Interceptors\n\n- global and custom\n\n```js\nauthFetch.interceptors.request.use(\n  (request) =\u003e {\n    request.headers.common['Accept'] = `application/json`;\n    console.log('request sent');\n    // must return request\n    return request;\n  },\n  (error) =\u003e {\n    return Promise.reject(error);\n  }\n);\n\nauthFetch.interceptors.response.use(\n  (response) =\u003e {\n    console.log('got response');\n    return response;\n  },\n  (error) =\u003e {\n    console.log(error.response);\n    if (error.response.status === 404) {\n      // do something\n      console.log('NOT FOUND');\n    }\n    return Promise.reject(error);\n  }\n);\n```\n\n\n# Redux Toolkit\n\n#### React Course\n\n[My React Course](https://www.udemy.com/course/react-tutorial-and-projects-course/?referralCode=FEE6A921AF07E2563CEF)\n\n#### Support\n\nFind the App Useful? [You can always buy me a coffee](https://www.buymeacoffee.com/johnsmilga)\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- CartItems.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\n# React Router 6\n\n#### React Course\n\n[My React Course](https://www.udemy.com/course/react-tutorial-and-projects-course/?referralCode=FEE6A921AF07E2563CEF)\n\n#### Support\n\nFind the App Useful? [You can always buy me a coffee](https://www.buymeacoffee.com/johnsmilga)\n\n#### Run Complete Project\n\n- index.js\n\n```js\n// import App from './App';\nimport App from './final/App';\n```\n\n#### Docs\n\n[React Router Docs](https://reactrouter.com/docs/en/v6/getting-started/overview)\n\n#### Install\n\n```sh\nnpm install react-router-dom@6\n```\n\n#### First Pages\n\n- App.js\n\n```js\nimport { BrowserRouter, Routes, Route } from 'react-router-dom';\n\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cdiv\u003ehome page\u003c/div\u003e} /\u003e\n        \u003cRoute\n          path='testing'\n          element={\n            \u003cdiv\u003e\n              \u003ch2\u003etesting \u003c/h2\u003e\n            \u003c/div\u003e\n          }\n        /\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n\nexport default App;\n```\n\n#### Components\n\n- App.js\n\n```js\nimport { BrowserRouter, Routes, Route } from 'react-router-dom';\nimport Home from './pages/Home';\nimport About from './pages/About';\nimport Products from './pages/Products';\n\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cHome /\u003e} /\u003e\n        \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n        \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n\nexport default App;\n```\n\n#### Links\n\n- Home.js, About.js\n\n```js\nimport { Link } from 'react-router-dom';\n\nconst Home = () =\u003e {\n  return (\n    \u003cdiv\u003e\n      \u003ch2\u003eHome Page\u003c/h2\u003e\n      \u003cLink to='/about' className='btn'\u003e\n        About\n      \u003c/Link\u003e\n      \u003ca href=\"\"\u003e\n    \u003c/div\u003e\n  );\n};\nexport default Home;\n```\n\n#### Error Page\n\n- App.js\n\n```js\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cHome /\u003e} /\u003e\n        \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n        \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n        \u003cRoute path='*' element={\u003cError /\u003e} /\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n```\n\n- Error.js\n\n```js\nimport { Link } from 'react-router-dom';\n\nconst Error = () =\u003e {\n  return (\n    \u003csection className='section'\u003e\n      \u003ch2\u003e404\u003c/h2\u003e\n      \u003cp\u003epage not found\u003c/p\u003e\n      \u003cLink to='/'\u003eback home\u003c/Link\u003e\n    \u003c/section\u003e\n  );\n};\nexport default Error;\n```\n\n#### Nested Pages\n\n- will refactor few times\n\n- App.js\n\n```js\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cHome /\u003e}\u003e\n          \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n          \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n          \u003cRoute path='*' element={\u003cError /\u003e} /\u003e\n        \u003c/Route\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n```\n\n#### Shared Layout\n\n- Home.js\n\n```js\nimport { Link, Outlet } from 'react-router-dom';\n\nconst Home = () =\u003e {\n  return (\n    \u003csection className='section'\u003e\n      \u003ch2\u003eHome Page\u003c/h2\u003e\n      \u003cOutlet /\u003e\n    \u003c/section\u003e\n  );\n};\nexport default Home;\n```\n\n#### Navbar\n\n- Navbar.js\n\n```js\nimport { Link } from 'react-router-dom';\n\nconst Navbar = () =\u003e {\n  return (\n    \u003cnav className='navbar'\u003e\n      \u003cLink to='/'\u003eHome\u003c/Link\u003e\n      \u003cLink to='/about'\u003eAbout\u003c/Link\u003e\n      \u003cLink to='/products'\u003eProducts\u003c/Link\u003e\n    \u003c/nav\u003e\n  );\n};\nexport default Navbar;\n```\n\n- Home.js\n\n```js\nimport { Link, Outlet } from 'react-router-dom';\nimport Navbar from '../components/Navbar';\nconst Home = () =\u003e {\n  return (\n    \u003c\u003e\n      \u003cNavbar /\u003e\n      \u003csection className='section'\u003e\n        \u003cOutlet /\u003e\n      \u003c/section\u003e\n    \u003c/\u003e\n  );\n};\nexport default Home;\n```\n\n#### Index Routes\n\n- Index routes render in the parent routes outlet at the parent route's path.\n- Index routes match when a parent route matches but none of the other children match.\n- Index routes are the default child route for a parent route.\n- Index routes render when the user hasn't clicked one of the items in a navigation list yet.\n\n- copy Home.js content\n- SharedLayout.js\n\n```js\nimport { Link, Outlet } from 'react-router-dom';\nimport Navbar from '../components/Navbar';\nconst SharedLayout = () =\u003e {\n  return (\n    \u003c\u003e\n      \u003cNavbar /\u003e\n      \u003csection className='section'\u003e\n        \u003cOutlet /\u003e\n      \u003c/section\u003e\n    \u003c/\u003e\n  );\n};\nexport default SharedLayout;\n```\n\n- Home.js\n\n```js\nconst Home = () =\u003e {\n  return (\n    \u003csection className='section'\u003e\n      \u003ch2\u003eHome Page\u003c/h2\u003e\n    \u003c/section\u003e\n  );\n};\nexport default Home;\n```\n\n- App.js\n\n```js\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cSharedLayout /\u003e}\u003e\n          \u003cRoute index element={\u003cHome /\u003e} /\u003e\n          \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n          \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n          \u003cRoute path='*' element={\u003cError /\u003e} /\u003e\n        \u003c/Route\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n```\n\n#### NavLink (style)\n\n- StyledNavbar.js\n\n```js\nimport { NavLink } from 'react-router-dom';\n\n\u003cnav className='navbar'\u003e\n  \u003cNavLink\n    to='/about'\n    style={({ isActive }) =\u003e {\n      return { color: isActive ? 'red' : 'grey' };\n    }}\n  \u003e\n    Home\n  \u003c/NavLink\u003e\n\u003c/nav\u003e;\n```\n\n#### NavLink (className)\n\n- StyledNavbar.js\n\n```js\n\u003cnav className='navbar'\u003e\n  \u003cNavLink\n    to='/'\n    className={({ isActive }) =\u003e (isActive ? 'link active' : 'link')}\n  \u003e\n    Home\n  \u003c/NavLink\u003e\n\u003c/nav\u003e\n```\n\n#### Reading URL Params\n\n- App.js\n\n```js\nfunction App() {\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cSharedLayout /\u003e}\u003e\n          \u003cRoute index element={\u003cHome /\u003e} /\u003e\n          \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n          \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n          \u003cRoute path='products/:productId' element={\u003cSingleProduct /\u003e} /\u003e\n          \u003cRoute path='*' element={\u003cError /\u003e} /\u003e\n        \u003c/Route\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n```\n\n#### Single Product\n\n- SingleProduct.js\n\n```js\nimport { Link, useParams } from 'react-router-dom';\nimport products from '../data';\nconst SingleProduct = () =\u003e {\n  const { productId } = useParams();\n\n  return (\n    \u003csection className='section product'\u003e\n      \u003ch2\u003e{productId}\u003c/h2\u003e\n      \u003cLink to='/products'\u003eback to products\u003c/Link\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default SingleProduct;\n```\n\n#### Products Page\n\n- Products.js\n\n```js\nimport { Link } from 'react-router-dom';\nimport products from '../data';\nconst Products = () =\u003e {\n  return (\n    \u003csection className='section'\u003e\n      \u003ch2\u003eproducts\u003c/h2\u003e\n      \u003cdiv className='products'\u003e\n        {products.map((product) =\u003e {\n          return (\n            \u003carticle key={product.id}\u003e\n              \u003ch5\u003e{product.name}\u003c/h5\u003e\n              \u003cLink to={`/products/${product.id}`}\u003emore info\u003c/Link\u003e\n            \u003c/article\u003e\n          );\n        })}\n      \u003c/div\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default Products;\n```\n\n#### Single Product\n\n- SingleProduct.js\n\n```js\nimport { Link, useParams } from 'react-router-dom';\nimport products from '../data';\nconst SingleProduct = () =\u003e {\n  const { productId } = useParams();\n  const product = products.find((product) =\u003e product.id === productId);\n  const { image, name } = product;\n\n  return (\n    \u003csection className='section product'\u003e\n      \u003cimg src={image} alt={name} /\u003e\n      \u003ch5\u003e{name}\u003c/h5\u003e\n      \u003cLink to='/products'\u003eback to products\u003c/Link\u003e\n    \u003c/section\u003e\n  );\n};\n\nexport default SingleProduct;\n```\n\n#### useNavigate()\n\n[ (?.) or Optional Chaining Explained](https://youtu.be/PuEGrylM1x8)\n\n- App.js\n\n```js\nfunction App() {\n  const [user, setUser] = useState(null);\n\n  return (\n    \u003cBrowserRouter\u003e\n      \u003cRoutes\u003e\n        \u003cRoute path='/' element={\u003cSharedLayout /\u003e}\u003e\n          \u003cRoute index element={\u003cHome /\u003e} /\u003e\n          \u003cRoute path='about' element={\u003cAbout /\u003e} /\u003e\n          \u003cRoute path='products' element={\u003cProducts /\u003e} /\u003e\n          \u003cRoute path='products/:productId' element={\u003cSingleProduct /\u003e} /\u003e\n          \u003cRoute path='login' element={\u003cLogin setUser={setUser} /\u003e} /\u003e\n          \u003cRoute path='dashboard' element={\u003cDashboard user={user} /\u003e} /\u003e\n          \u003cRoute path='*' element={\u003cError /\u003e} /\u003e\n        \u003c/Route\u003e\n      \u003c/Routes\u003e\n    \u003c/BrowserRouter\u003e\n  );\n}\n```\n\n- Login.js\n\n```js\n import { useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nconst Login = ({ setUser }) =\u003e {\n  const [name, setName] = useState('');\n  const [email, setEmail] = useState('');\n\n  const navigate = useNavigate();\n\n  const handleSubmit = async (e) =\u003e {\n    e.preventDefault();\n    if (!name || !email) return;\n    setUser({ name: name, email: email });\n    navigate('/dashboard');\n  };\n\n```\n\n[ (?.) or Optional Chaining Explained](https://youtu.be/PuEGrylM1x8)\n\n- Dashboard.js\n\n```js\nconst Dashboard = ({ user }) =\u003e {\n  return (\n    \u003csection className='section'\u003e\n      \u003ch4\u003eHello, {user?.name}\u003c/h4\u003e\n    \u003c/section\u003e\n  );\n};\nexport default Dashboard;\n```\n\n#### Protected Route\n\n- App.js\n\n```js\n\u003cRoute\n  path='dashboard'\n  element={\n    \u003cProtectedRoute user={user}\u003e\n      \u003cDashboard user={user} /\u003e\n    \u003c/ProtectedRoute\u003e\n  }\n/\u003e\n```\n\n- ProtectedRoute.js\n\n```js\nimport { Navigate } from 'react-router-dom';\n\nconst ProtectedRoute = ({ children, user }) =\u003e {\n  if (!user) {\n    return \u003cNavigate to='/' /\u003e;\n  }\n  return children;\n};\n\nexport default ProtectedRoute;\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftabotcharlesbessong%2Fall-react-from-john-smilga","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftabotcharlesbessong%2Fall-react-from-john-smilga","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftabotcharlesbessong%2Fall-react-from-john-smilga/lists"}