- Birthday Reminder
- Tours
- Reviews
- Questions
- Menu
- Tabs
- Slider
- Lorem Ipsum Generator
- Color Shades Generator
- Grocery Bud
- Navbar
- Modal And Sidebar
- Stripe Submenus
- Cart
- Cocktails
- Markdown Preview
- Random Person
- Pagination
- Stock Photos
- Dark Mode
- Movie DB
- Hacker News
- Quiz
axios tutorial section
npm install axios
<script src='https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js'></script>
-
import axios
-
axios.get(url)
-
axios.post(url)
-
axios.patch/put(url)
-
axios.delete(ulr)
-
default get axios(url)
-
returns a promise
-
response data located in data property
-
error in error.response
import axios from 'axios';
const fetchData = async () => {
try {
// axios.get(), axios.post(),axios.put(), axios.delete()
const response = await axios(url);
console.log(response);
} catch (error) {
console.log(error.response);
}
};
-
second argument
-
axios.get(url,{})
-
third argument in requests with data
-
axios.post(url,{data},{})
const fetchDadJoke = async () => {
try {
const { data } = await axios(url, {
headers: {
Accept: 'application/json',
},
});
// console.log(data);
setJoke(data.joke);
} catch (error) {
console.log(error.response);
}
};
- send data to the server
- axios.post(url, { data })
- more options (auth header) - axios.post(url, { data },{})
try {
const resp = await axios.post(url, { data });
} catch (error) {
console.log(error.response.data);
}
axios.defaults.headers.common['Accept'] = 'application/json';
axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded';
const authFetch = axios.create({
baseURL: 'https://course-api.com',
headers: {
Accept: 'application/json',
},
});
- global and custom
authFetch.interceptors.request.use(
(request) => {
request.headers.common['Accept'] = `application/json`;
console.log('request sent');
// must return request
return request;
},
(error) => {
return Promise.reject(error);
}
);
authFetch.interceptors.response.use(
(response) => {
console.log('got response');
return response;
},
(error) => {
console.log(error.response);
if (error.response.status === 404) {
// do something
console.log('NOT FOUND');
}
return Promise.reject(error);
}
);
Find the App Useful? You can always buy me a coffee
npx create-react-app my-app --template redux
- @latest
npx create-react-app@latest my-app --template redux
npm install @reduxjs/toolkit react-redux
consists of few libraries
- redux (core library, state management)
- immer (allows to mutate state)
- redux-thunk (handles async actions)
- reselect (simplifies reducer functions)
- redux devtools
- combine reducers
connects our app to redux
- create store.js
import { configureStore } from '@reduxjs/toolkit';
export const store = configureStore({
reducer: {},
});
- index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
// import store and provider
import { store } from './store';
import { Provider } from 'react-redux';
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
);
- application feature
- create features folder/cart
- create cartSlice.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
cartItems: [],
amount: 0,
total: 0,
isLoading: true,
};
const cartSlice = createSlice({
name: 'cart',
initialState,
});
console.log(cartSlice);
export default cartSlice.reducer;
- store.js
import { configureStore } from '@reduxjs/toolkit';
import cartReducer from './features/cart/cartSlice';
export const store = configureStore({
reducer: {
cart: cartReducer,
},
});
- extension
- create components/Navbar.js
import { CartIcon } from '../icons';
import { useSelector } from 'react-redux';
const Navbar = () => {
const { amount } = useSelector((state) => state.cart);
return (
<nav>
<div className='nav-center'>
<h3>redux toolkit</h3>
<div className='nav-container'>
<CartIcon />
<div className='amount-container'>
<p className='total-amount'>{amount}</p>
</div>
</div>
</div>
</nav>
);
};
export default Navbar;
nav svg {
width: 40px;
color: var(--clr-white);
}
- cartSlice.js
import cartItems from '../../cartItems';
const initialState = {
cartItems: cartItems,
amount: 0,
total: 0,
isLoading: true,
};
- create CartContainer.js and CartItem.js
- CartContainer.js
import React from 'react';
import CartItem from './CartItem';
import { useSelector } from 'react-redux';
const CartContainer = () => {
const { cartItems, total, amount } = useSelector((state) => state.cart);
if (amount < 1) {
return (
<section className='cart'>
{/* cart header */}
<header>
<h2>your bag</h2>
<h4 className='empty-cart'>is currently empty</h4>
</header>
</section>
);
}
return (
<section className='cart'>
{/* cart header */}
<header>
<h2>your bag</h2>
</header>
{/* cart items */}
<div>
{cartItems.map((item) => {
return <CartItem key={item.id} {...item} />;
})}
</div>
{/* cart footer */}
<footer>
<hr />
<div className='cart-total'>
<h4>
total <span>${total}</span>
</h4>
</div>
<button className='btn clear-btn'>clear cart</button>
</footer>
</section>
);
};
export default CartContainer;
- CartItems.js
import React from 'react';
import { ChevronDown, ChevronUp } from '../icons';
const CartItem = ({ id, img, title, price, amount }) => {
return (
<article className='cart-item'>
<img src={img} alt={title} />
<div>
<h4>{title}</h4>
<h4 className='item-price'>${price}</h4>
{/* remove button */}
<button className='remove-btn'>remove</button>
</div>
<div>
{/* increase amount */}
<button className='amount-btn'>
<ChevronUp />
</button>
{/* amount */}
<p className='amount'>{amount}</p>
{/* decrease amount */}
<button className='amount-btn'>
<ChevronDown />
</button>
</div>
</article>
);
};
export default CartItem;
- cartSlice.js
- Immer library
const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
clearCart: (state) => {
state.cartItems = [];
},
},
});
export const { clearCart } = cartSlice.actions;
- create action
const ACTION_TYPE = 'ACTION_TYPE';
const actionCreator = (payload) => {
return { type: ACTION_TYPE, payload: payload };
};
- CartContainer.js
import React from 'react';
import CartItem from './CartItem';
import { useDispatch, useSelector } from 'react-redux';
const CartContainer = () => {
const dispatch = useDispatch();
return (
<button
className='btn clear-btn'
onClick={() => {
dispatch(clearCart());
}}
>
clear cart
</button>
);
};
export default CartContainer;
- cartSlice.js
import { createSlice } from '@reduxjs/toolkit';
import cartItems from '../../cartItems';
const initialState = {
cartItems: [],
amount: 0,
total: 0,
isLoading: true,
};
const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
clearCart: (state) => {
state.cartItems = [];
},
removeItem: (state, action) => {
const itemId = action.payload;
state.cartItems = state.cartItems.filter((item) => item.id !== itemId);
},
increase: (state, { payload }) => {
const cartItem = state.cartItems.find((item) => item.id === payload.id);
cartItem.amount = cartItem.amount + 1;
},
decrease: (state, { payload }) => {
const cartItem = state.cartItems.find((item) => item.id === payload.id);
cartItem.amount = cartItem.amount - 1;
},
calculateTotals: (state) => {
let amount = 0;
let total = 0;
state.cartItems.forEach((item) => {
amount += item.amount;
total += item.amount * item.price;
});
state.amount = amount;
state.total = total;
},
},
});
export const { clearCart, removeItem, increase, decrease, calculateTotals } =
cartSlice.actions;
export default cartSlice.reducer;
- CartItem.js
import React from 'react';
import { ChevronDown, ChevronUp } from '../icons';
import { useDispatch } from 'react-redux';
import { removeItem, increase, decrease } from '../features/cart/cartSlice';
const CartItem = ({ id, img, title, price, amount }) => {
const dispatch = useDispatch();
return (
<article className='cart-item'>
<img src={img} alt={title} />
<div>
<h4>{title}</h4>
<h4 className='item-price'>${price}</h4>
{/* remove button */}
<button
className='remove-btn'
onClick={() => {
dispatch(removeItem(id));
}}
>
remove
</button>
</div>
<div>
{/* increase amount */}
<button
className='amount-btn'
onClick={() => {
dispatch(increase({ id }));
}}
>
<ChevronUp />
</button>
{/* amount */}
<p className='amount'>{amount}</p>
{/* decrease amount */}
<button
className='amount-btn'
onClick={() => {
if (amount === 1) {
dispatch(removeItem(id));
return;
}
dispatch(decrease({ id }));
}}
>
<ChevronDown />
</button>
</div>
</article>
);
};
export default CartItem;
- App.js
import { useEffect } from 'react';
import Navbar from './components/Navbar';
import CartContainer from './components/CartContainer';
import { useSelector, useDispatch } from 'react-redux';
import { calculateTotals } from './features/cart/cartSlice';
function App() {
const { cartItems } = useSelector((state) => state.cart);
const dispatch = useDispatch();
useEffect(() => {
dispatch(calculateTotals());
}, [cartItems]);
return (
<main>
<Navbar />
<CartContainer />
</main>
);
}
export default App;
- create components/Modal.js
const Modal = () => {
return (
<aside className='modal-container'>
<div className='modal'>
<h4>Remove all items from your shopping cart?</h4>
<div className='btn-container'>
<button type='button' className='btn confirm-btn'>
confirm
</button>
<button type='button' className='btn clear-btn'>
cancel
</button>
</div>
</div>
</aside>
);
};
export default Modal;
- App.js
return (
<main>
<Modal />
<Navbar />
<CartContainer />
</main>
);
- create features/modal/modalSlice.js
import { createSlice } from '@reduxjs/toolkit';
const initialState = {
isOpen: false,
};
const modalSlice = createSlice({
name: 'modal',
initialState,
reducers: {
openModal: (state, action) => {
state.isOpen = true;
},
closeModal: (state, action) => {
state.isOpen = false;
},
},
});
export const { openModal, closeModal } = modalSlice.actions;
export default modalSlice.reducer;
- App.js
const { isOpen } = useSelector((state) => state.modal);
return (
<main>
{isOpen && <Modal />}
<Navbar />
<CartContainer />
</main>
);
- CartContainer.js
import { openModal } from '../features/modal/modalSlice';
return (
<button
className='btn clear-btn'
onClick={() => {
dispatch(openModal());
}}
>
clear cart
</button>
);
- Modal.js
import { closeModal } from '../features/modal/modalSlice';
import { useDispatch } from 'react-redux';
import { clearCart } from '../features/cart/cartSlice';
const Modal = () => {
const dispatch = useDispatch();
return (
<aside className='modal-container'>
<div className='modal'>
<h4>Remove all items from your shopping cart?</h4>
<div className='btn-container'>
<button
type='button'
className='btn confirm-btn'
onClick={() => {
dispatch(clearCart());
dispatch(closeModal());
}}
>
confirm
</button>
<button
type='button'
className='btn clear-btn'
onClick={() => {
dispatch(closeModal());
}}
>
cancel
</button>
</div>
</div>
</aside>
);
};
export default Modal;
-
cartSlice.js
-
action type
-
callback function
-
lifecycle actions
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
const url = 'https://course-api.com/react-useReducer-cart-project';
export const getCartItems = createAsyncThunk('cart/getCartItems', () => {
return fetch(url)
.then((resp) => resp.json())
.catch((err) => console.log(error));
});
const cartSlice = createSlice({
name: 'cart',
initialState,
extraReducers: {
[getCartItems.pending]: (state) => {
state.isLoading = true;
},
[getCartItems.fulfilled]: (state, action) => {
console.log(action);
state.isLoading = false;
state.cartItems = action.payload;
},
[getCartItems.rejected]: (state) => {
state.isLoading = false;
},
},
});
- App.js
import { calculateTotals, getCartItems } from './features/cart/cartSlice';
function App() {
const { cartItems, isLoading } = useSelector((state) => state.cart);
useEffect(() => {
dispatch(getCartItems());
}, []);
if (isLoading) {
return (
<div className='loading'>
<h1>Loading...</h1>
</div>
);
}
return (
<main>
{isOpen && <Modal />}
<Navbar />
<CartContainer />
</main>
);
}
export default App;
npm install axios
- cartSlice.js
export const getCartItems = createAsyncThunk(
'cart/getCartItems',
async (name, thunkAPI) => {
try {
// console.log(name);
// console.log(thunkAPI);
// console.log(thunkAPI.getState());
// thunkAPI.dispatch(openModal());
const resp = await axios(url);
return resp.data;
} catch (error) {
return thunkAPI.rejectWithValue('something went wrong');
}
}
);
Find the App Useful? You can always buy me a coffee
- index.js
// import App from './App';
import App from './final/App';
npm install react-router-dom@6
- App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<div>home page</div>} />
<Route
path='testing'
element={
<div>
<h2>testing </h2>
</div>
}
/>
</Routes>
</BrowserRouter>
);
}
export default App;
- App.js
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Home from './pages/Home';
import About from './pages/About';
import Products from './pages/Products';
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
</Routes>
</BrowserRouter>
);
}
export default App;
- Home.js, About.js
import { Link } from 'react-router-dom';
const Home = () => {
return (
<div>
<h2>Home Page</h2>
<Link to='/about' className='btn'>
About
</Link>
<a href="">
</div>
);
};
export default Home;
- App.js
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
<Route path='*' element={<Error />} />
</Routes>
</BrowserRouter>
);
}
- Error.js
import { Link } from 'react-router-dom';
const Error = () => {
return (
<section className='section'>
<h2>404</h2>
<p>page not found</p>
<Link to='/'>back home</Link>
</section>
);
};
export default Error;
-
will refactor few times
-
App.js
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />}>
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
<Route path='*' element={<Error />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- Home.js
import { Link, Outlet } from 'react-router-dom';
const Home = () => {
return (
<section className='section'>
<h2>Home Page</h2>
<Outlet />
</section>
);
};
export default Home;
- Navbar.js
import { Link } from 'react-router-dom';
const Navbar = () => {
return (
<nav className='navbar'>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
<Link to='/products'>Products</Link>
</nav>
);
};
export default Navbar;
- Home.js
import { Link, Outlet } from 'react-router-dom';
import Navbar from '../components/Navbar';
const Home = () => {
return (
<>
<Navbar />
<section className='section'>
<Outlet />
</section>
</>
);
};
export default Home;
-
Index routes render in the parent routes outlet at the parent route's path.
-
Index routes match when a parent route matches but none of the other children match.
-
Index routes are the default child route for a parent route.
-
Index routes render when the user hasn't clicked one of the items in a navigation list yet.
-
copy Home.js content
-
SharedLayout.js
import { Link, Outlet } from 'react-router-dom';
import Navbar from '../components/Navbar';
const SharedLayout = () => {
return (
<>
<Navbar />
<section className='section'>
<Outlet />
</section>
</>
);
};
export default SharedLayout;
- Home.js
const Home = () => {
return (
<section className='section'>
<h2>Home Page</h2>
</section>
);
};
export default Home;
- App.js
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<SharedLayout />}>
<Route index element={<Home />} />
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
<Route path='*' element={<Error />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- StyledNavbar.js
import { NavLink } from 'react-router-dom';
<nav className='navbar'>
<NavLink
to='/about'
style={({ isActive }) => {
return { color: isActive ? 'red' : 'grey' };
}}
>
Home
</NavLink>
</nav>;
- StyledNavbar.js
<nav className='navbar'>
<NavLink
to='/'
className={({ isActive }) => (isActive ? 'link active' : 'link')}
>
Home
</NavLink>
</nav>
- App.js
function App() {
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<SharedLayout />}>
<Route index element={<Home />} />
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
<Route path='products/:productId' element={<SingleProduct />} />
<Route path='*' element={<Error />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- SingleProduct.js
import { Link, useParams } from 'react-router-dom';
import products from '../data';
const SingleProduct = () => {
const { productId } = useParams();
return (
<section className='section product'>
<h2>{productId}</h2>
<Link to='/products'>back to products</Link>
</section>
);
};
export default SingleProduct;
- Products.js
import { Link } from 'react-router-dom';
import products from '../data';
const Products = () => {
return (
<section className='section'>
<h2>products</h2>
<div className='products'>
{products.map((product) => {
return (
<article key={product.id}>
<h5>{product.name}</h5>
<Link to={`/products/${product.id}`}>more info</Link>
</article>
);
})}
</div>
</section>
);
};
export default Products;
- SingleProduct.js
import { Link, useParams } from 'react-router-dom';
import products from '../data';
const SingleProduct = () => {
const { productId } = useParams();
const product = products.find((product) => product.id === productId);
const { image, name } = product;
return (
<section className='section product'>
<img src={image} alt={name} />
<h5>{name}</h5>
<Link to='/products'>back to products</Link>
</section>
);
};
export default SingleProduct;
(?.) or Optional Chaining Explained
- App.js
function App() {
const [user, setUser] = useState(null);
return (
<BrowserRouter>
<Routes>
<Route path='/' element={<SharedLayout />}>
<Route index element={<Home />} />
<Route path='about' element={<About />} />
<Route path='products' element={<Products />} />
<Route path='products/:productId' element={<SingleProduct />} />
<Route path='login' element={<Login setUser={setUser} />} />
<Route path='dashboard' element={<Dashboard user={user} />} />
<Route path='*' element={<Error />} />
</Route>
</Routes>
</BrowserRouter>
);
}
- Login.js
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
const Login = ({ setUser }) => {
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const navigate = useNavigate();
const handleSubmit = async (e) => {
e.preventDefault();
if (!name || !email) return;
setUser({ name: name, email: email });
navigate('/dashboard');
};
(?.) or Optional Chaining Explained
- Dashboard.js
const Dashboard = ({ user }) => {
return (
<section className='section'>
<h4>Hello, {user?.name}</h4>
</section>
);
};
export default Dashboard;
- App.js
<Route
path='dashboard'
element={
<ProtectedRoute user={user}>
<Dashboard user={user} />
</ProtectedRoute>
}
/>
- ProtectedRoute.js
import { Navigate } from 'react-router-dom';
const ProtectedRoute = ({ children, user }) => {
if (!user) {
return <Navigate to='/' />;
}
return children;
};
export default ProtectedRoute;