Skip to content

Commit

Permalink
Performance optimizations
Browse files Browse the repository at this point in the history
- React lazy and Suspense added to router components
- added memo to some components
- added useCallback to some functions
  • Loading branch information
Felipe Spengler committed Apr 3, 2024
1 parent 6b9e3ba commit 128e49b
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 33 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ My React experience has been on and off as my career led to be a Senior Frontend
- Shop / Category pages with functional Add To Cart button + Minicart + Bag icon counter
- Cart/Minicart quantity changes + product removal + counter update
- Categories data comes from Firebase.
- Code performance improvements:
- added `useCallback` to avoid redefininig functions;
- added `memo` to some components to avoind unnecessary re-renders;
- added react `lazy` and `Suspense` to App for better bundle/code splitting;

## Extra features / learning by me (not part of the course)
- Products have currency and proper price format.
Expand Down
32 changes: 18 additions & 14 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { useEffect } from 'react';
import { useEffect, lazy, Suspense } from 'react';
import { Routes, Route } from "react-router-dom";
import { useDispatch } from 'react-redux';

import { authChangedListener, createUserDocFromAuth } from './utils/firebase/firebase.utils.js';
import { setCurrentUser } from './store/user.reducer.js';
import SpinnerComponent from './components/spinner/spinner.component.jsx';

import Navigation from './routes/navigation/navigation.component.jsx';
import Home from './routes/home/home.component';
import Login from './routes/login/login.component.jsx';
import Shop from './routes/shop/shop.component.jsx';
import CheckoutComponent from './routes/checkout/checkout.component.jsx';
const Navigation = lazy(() => import('./routes/navigation/navigation.component'));
const Home = lazy(() => import('./routes/home/home.component'));
const Login = lazy(() => import('./routes/login/login.component'));
const Shop = lazy(() => import('./routes/shop/shop.component'));
const CheckoutComponent = lazy(() => import('./routes/checkout/checkout.component'));

const App = () => {

Expand All @@ -27,14 +28,17 @@ const App = () => {
}, []); // eslint-disable-line react-hooks/exhaustive-deps

return (
<Routes>
<Route path='/' element={<Navigation />}>
<Route index element={<Home />} />
<Route path='shop/*' element={<Shop />} />
<Route path='login' element={<Login />} />
<Route path='checkout' element={<CheckoutComponent />} />
</Route>
</Routes>
<Suspense fallback={<SpinnerComponent />}>

<Routes>
<Route path='/' element={<Navigation />}>
<Route index element={<Home />} />
<Route path='shop/*' element={<Shop />} />
<Route path='login' element={<Login />} />
<Route path='checkout' element={<CheckoutComponent />} />
</Route>
</Routes>
</Suspense>
)
}

Expand Down
5 changes: 3 additions & 2 deletions src/components/cart/cart-icon.component.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@ import { toggleMinicart } from '../../store/minicart.reducer';

import bagIcon from '../../assets/shopping-bag.svg'
import './cart-icon.styles.scss';
import { useCallback } from 'react';

const CartIcon = () => {
const dispatch = useDispatch();
const bagCount = useSelector(selectBagCount);
const openMinicart = useSelector(selectOpenMinicart);

const handleMinicartToggle = () => {
const handleMinicartToggle = useCallback(() => {
dispatch(toggleMinicart(!openMinicart));
}
}, [openMinicart]); //eslint-disable-line react-hooks/exhaustive-deps

return (
<button type='button' className='cart-icon-container' onClick={handleMinicartToggle}>
Expand Down
7 changes: 5 additions & 2 deletions src/components/cart/cart-item.component.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { memo } from 'react';

import './cart-item.styles.scss';

const CartItem = ({ cartItem }) => {
// eslint-disable-next-line react/display-name
const CartItem = memo(({ cartItem }) => {
const { name, imageUrl, price, quantity } = cartItem;
return (
<div className='minicart-item'>
Expand All @@ -14,6 +17,6 @@ const CartItem = ({ cartItem }) => {
</div>
</div>
);
}
})

export default CartItem;
11 changes: 6 additions & 5 deletions src/components/cart/minicart.component.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect } from 'react';
import { memo, useCallback, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { Link, useLocation } from 'react-router-dom';

Expand All @@ -8,7 +8,8 @@ import { toggleMinicart } from '../../store/minicart.reducer';
import CartItem from './cart-item.component.jsx';
import './minicart.styles.scss';

const Minicart = () => {
// eslint-disable-next-line react/display-name
const Minicart = memo(() => {
const dispatch = useDispatch();
const location = useLocation();
const openMinicart = useSelector(selectOpenMinicart);
Expand All @@ -21,9 +22,9 @@ const Minicart = () => {
}
}, [location]); //eslint-disable-line react-hooks/exhaustive-deps

const closeMinicart = () => {
const closeMinicart = useCallback(() => {
dispatch(toggleMinicart(false))
}
}, []);//eslint-disable-line react-hooks/exhaustive-deps

return (
<div
Expand Down Expand Up @@ -53,6 +54,6 @@ const Minicart = () => {
</div>
</div>
);
}
})

export default Minicart;
10 changes: 5 additions & 5 deletions src/components/login-form/login-form.component.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useCallback, useState } from 'react';
import {
signInWithGooglePopup,
loginUserWithEmailPwd
Expand All @@ -16,13 +16,13 @@ const LoginForm = () => {
const [formFields, setFormFields] = useState(defaultFormFields);
const { email, password } = formFields;

const clearForm = () => {
const clearForm = useCallback(() => {
setFormFields(defaultFormFields);
};
}, []);

const loginWithGoogle = async () => {
const loginWithGoogle = useCallback(async () => {
await signInWithGooglePopup();
};
}, []);

const handleSubmit = async (event) => {
event.preventDefault();
Expand Down
10 changes: 5 additions & 5 deletions src/components/register-form/register-form.component.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from 'react';
import { useCallback, useState } from 'react';
import FormInput from '../form-input/form-input.component';
import Button from '../button/button.component';
import { createUserWithEmailPwd, createUserDocFromAuth } from '../../utils/firebase/firebase.utils';
Expand All @@ -18,12 +18,12 @@ const RegisterForm = () => {
// Destructure the passed object above to have their values as variables
const { displayName, email, password, confirmPassword } = formFields;

const clearForm = () => {
const clearForm = useCallback(() => {
setFormFields(defaultFormFields);
};
}, []);

// Handle the submit, async as it uses external auth
const handleSubmit = async (event) => {
const handleSubmit = useCallback(async (event) => {
event.preventDefault();

//Verify is password matches, can extend this to add more checks like format, length,etc
Expand All @@ -49,7 +49,7 @@ const RegisterForm = () => {
console.log(`User creation error: ${error.message}`)
}
}
};
}, [formFields]); //eslint-disable-line react-hooks/exhaustive-deps

// Basic function called by the inputs onChange event
const handleChange = (event) => {
Expand Down

0 comments on commit 128e49b

Please sign in to comment.