- Published on
Ways to Optimize your React/Nextjs Application
- Authors
- Name
- Kim, Dong-Wook
Table of Contents
Intro
While making React/Nextjs Boilerplate, I read some FE optimization technique(like React Context Optimizing, Tree Shaking). So I will introduce how to apply these thing in your app.
Tree-Shaking
Tree-Shaking means remove unusable code in your project. This term quite directly represents the meaning of the word. Because when you make your own React/Nextjs App, that has tree like shape, but also downloaded packages too.
import _ from 'lodash';
import { useCallback, useEffect } from 'react';
export default function useWindowResize(callback: () => void, delay: number) {
const handleResize = useCallback(() => {
callback();
}, [callback]);
useEffect(() => {
const throttled = _.throttle(handleResize, delay);
window.addEventListener('resize', throttled);
handleResize();
return () => window.removeEventListener('resize', throttled);
}, [handleResize, delay]);
}
When you write components using lodash modules. we usually write code like above. But using package like this is not good for you project. Import full package in your code increases the size of build. Actually, I just write import _ from 'lodash'
to use throttle function the bundle size increases 531.35KB, just for one line of code. To avoid this, you should use it like below.
{...}
import throttle from 'lodash/throttle'
{...}
.import the package you want to use only
{...}
import { throttle } from 'lodash-es'
{...}
or use lodash-es(lodah-es is written in ES Module way. So tree-shaking will be applied automatically by webpack)
Tree-Shaked Result
you can see, there is no lodash.js cause it is too small.
Constate
Wrap Context usingI use React Context to implement auto-login, avoid prop-drilling, Etc.. React Context is very powerful when you need global state. But it doesn't do performance optimization. Assume that a component uses specific context value & another context value updated, that component will be re-rendered. For this reason, you should use React Context carefully.
According to this reason, when you use it, if it is not related to each other, you should do separation of interests. It means you should write context separately.
Check Advent Calendar code
export const useModal = (): IModalContext => useContext(ModalContext);
export const ModalProvider: FC = ({ children }) => {
const [modal, setModal] = {...};
const closeModal = {...}
const openModal = {...}
const openLoginModal = {...}
const openCalendarInfoModal = {...}
const openCalendarCreateModal = {...}
return (
<ModalContext.Provider
value={{
...
}}
>
{children}
</ModalContext.Provider>
);
};
This code is not optmized. When modal state is updated, every components & functions that reference modal, setModal will be re-rendered. To prevent this, we should separate like this.
export const useModal = (): IModalContext => useContext(ModalContext);
export const ModalProvider: FC = ({ children }) => {
const [modal, setModal] = {...};
const closeModal = {...}
const openModal = {...}
const openLoginModal = {...}
const openCalendarInfoModal = {...}
const openCalendarCreateModal = {...}
return (
<ModalContext.Provider value={modal}>
<ModalUpdateContext.Provider value={setModal}>
{children}
</ModalUpdateContext.Provider>
</ModalContext.Provider>
);
};
But this is too hassle to apply. At this time, Constate module is really shines to us. To do the same thing above, it could be implemented like below.
const useModal = () => {
const [modal, setModal] = useState<ModalShape | null>(null)
const closeModal = {...}
const openModal = {...}
const openSignUpModal = {...}
const openSignInModal = = {...}
return { modal, openSignUpModal, openSignInModal, closeModal }
}
const [
ModalProvider,
useModalInfo,
useSignUpModal,
useSignInModal,
useCloseModal,
] = constate(
useModal,
(value) => value.modal,
(value) => value.openSignUpModal,
(value) => value.openSignInModal,
(value) => value.closeModal
)
export {
ModalProvider,
useModalInfo,
useSignUpModal,
useSignInModal,
useCloseModal,
}
<Composer components={[UserAuthProvider, ModalProvider]}>
<Component {...pageProps} />
<ModalContainer />
</Composer>
Constate make Context Hook automatically. It makes separation of interests easily.
Conclusion
I hope you apply these thing depends on your project size. If it is small, it increases learning curve.