How to setup Vite React App!
Introduction ๐ข
Hey geeky devs, today we are going to build a an awesome Vite React App Project Setup that will grow as our Client unnecessary expectations. ๐ฅด
Prerequisites ๐ฏ
Little bit knowledge in JavaScript/TypeScript
Little bit knowledge in React
A whole lot of motivation (naa just kidding, this one is easy)
Setting Up ๐ ๏ธ
Node > 20 LTS
Your Favourite IDE
npm or yarn or pnpm or whatever floats your boat โด๏ธ
Why React? ๐ค
React is still, and always will be, one of the best ways for a beginner to start Frontend development and build a career in frontend. According to the Stack Overflow Survey 2024, React is still the top choice for professional developers and people who are learning to code! That says a lot.
Step 1: Build A Vite React App
Use the following command to build a React Vite App and choose the options as mentioned below.
yarn create vite
Step 2: Install the Required Library
1st: Install the library that makes styling easier and reduces the use of CSS
This section depends on your preferences and which UI library you prefer. However, my suggestion is to choose the one that will simplify development as your project grows. I would go with Material UI for this tutorial.
yarn add @mui/material @emotion/react @emotion/styled @mui/icons-material -D
2nd: Install and Setup Eslint and Prettier
It's convenient that Vite automatically configures ESLint when setting up an app. Next, we just need to configure Prettier.
yarn add prettier eslint-config-prettier eslint-plugin-prettier -D
3rd: Install State Management Library
This section depends on your preferences, as React offers many options to choose from. The most popular state management libraries include Redux, Zustand, and Recoil, among others.
Choose the one that best aligns with your project requirements. For simplicity of this tutorial I will go with plain Context API
Step 3: Folder Structure
Here is the breakdown for the folder structure each module wise
vite-react-app/
โโโ public/
โโโ src/
โ โโโ assets/
โ โโโ components/
โ โโโ hooks/
โ โโโ pages/
โ โโโ config/
| โโโ contexts/
โ โโโ types/
โ โโโ utils/
โ โโโ App.tsx
โ โโโ main.tsx
| โโโ index.css
โ โโโ vite-env.d.ts
Assets
src/
โโโ assets/
โ โโโ icons/
โ โ โโโ message-icon.svg
โ โ โโโ index.ts
โ โโโ images/
โ โ โโโ hero.svg
โ โ โโโ index.ts
Components
src/
โโโ components/
โ โโโ button/
โ โ โโโ CustomButton.tsx
โ โ โโโ index.ts
โ โโโ header/
โ โ โโโ CustomHeader.tsx
โ โ โโโ index.ts
Context
src/
โโโ context/
โ โโโ HttpMethodContext.ts
HttpMethodContext.ts
import axios from 'axios';
import React, { createContext, useCallback, useContext, useState } from 'react';
import { ApiResponseData } from '../types/api';
import envConfig from '../config/env.config';
interface HttpMethodContextType {
showApiLoader: boolean;
setShowApiLoader: React.Dispatch<React.SetStateAction<boolean>>;
get: (endpoint: string, showLoader?: boolean) => Promise<ApiResponseData>;
post: (
endpoint: string,
data: object | Array<object>,
showLoader?: boolean,
header?: object
) => Promise<ApiResponseData>;
put: (
endpoint: string,
data: object | Array<object>,
showLoader?: boolean
) => Promise<ApiResponseData>;
deleteMe: (
endpoint: string,
body: Array<object> | object,
showLoader?: boolean
) => Promise<ApiResponseData>;
}
export const HttpMethodContext = createContext<
HttpMethodContextType | undefined
>(undefined);
const AxiosService = axios.create({
baseURL: envConfig.API_URL
});
const createApiErrorResponse = (error: unknown): ApiResponseData => {
let errorMsg = 'Something went wrong';
if (error instanceof String) {
errorMsg = error.toString();
} else if (error instanceof Error) {
errorMsg = error.message;
}
return { success: false, errorMsg, response: {} };
};
export const HttpMethodContextProvider: React.FC<{
children: React.ReactNode;
}> = ({ children }) => {
const [showApiLoader, setShowApiLoader] = useState(false);
AxiosService.defaults.headers.common.Accept = 'application/json';
AxiosService.defaults.headers.common['Content-Type'] = 'application/json';
const get = useCallback(
async (endpoint: string, showLoader = true): Promise<ApiResponseData> => {
setShowApiLoader(showLoader);
return AxiosService.get(endpoint)
.then((res) => {
console.log(`GET: ${endpoint}:`, res.status);
return {
success: true,
errorMsg: '',
response: res.data
};
})
.catch((err) => {
console.log(`๐ GET: ${endpoint}:`, err?.response?.data ?? err);
return createApiErrorResponse(err);
})
.finally(() => setShowApiLoader(false));
},
[setShowApiLoader]
);
const post = useCallback(
async (
endpoint: string,
data: object | Array<object>,
showLoader = true,
headers = {}
): Promise<ApiResponseData> => {
setShowApiLoader(showLoader);
return AxiosService.post(endpoint, data, headers)
.then((res) => {
console.log(`POST: ${endpoint} res`, res.status);
return {
success: true,
errorMsg: '',
response: res.data
};
})
.catch((err) => {
console.log(`๐ POST - ${endpoint} err`, err?.response?.data ?? err);
return createApiErrorResponse(err);
})
.finally(() => setShowApiLoader(false));
},
[setShowApiLoader]
);
const put = useCallback(
async (
endpoint: string,
data: object | Array<object>,
showLoader = true
): Promise<ApiResponseData> => {
setShowApiLoader(showLoader);
return AxiosService.put(endpoint, data)
.then((res) => {
console.log(`PUT: ${endpoint} res`, res.status);
return {
success: true,
errorMsg: '',
response: res.data
};
})
.catch((err) => {
console.log(`๐ PUT - ${endpoint} err`, err?.response?.data ?? err);
return createApiErrorResponse(err);
})
.finally(() => setShowApiLoader(false));
},
[setShowApiLoader]
);
const deleteMe = useCallback(
async (
endpoint: string,
body: Array<object> | object,
showLoader = true
): Promise<ApiResponseData> => {
setShowApiLoader(showLoader);
return AxiosService.delete(endpoint, { data: body })
.then((res) => {
console.log(`DELETE: ${endpoint} res`, res.status);
return {
success: true,
errorMsg: '',
response: res.data
};
})
.catch((err) => {
console.log(
`๐ DELETE - ${endpoint} err`,
err?.response?.data ?? err
);
return createApiErrorResponse(err);
})
.finally(() => setShowApiLoader(false));
},
[setShowApiLoader]
);
return (
<HttpMethodContext.Provider
value={{ showApiLoader, setShowApiLoader, get, post, put, deleteMe }}
>
{children}
</HttpMethodContext.Provider>
);
};
export const useHttpMethodContext = () => {
const context = useContext(HttpMethodContext);
if (!context) {
throw new Error('useHttpMethodContext must be used within a UserProvider');
}
return context;
};
Hooks
src/
โโโ hooks/
โ โโโ api/
โ โ โโโ useUserApi.ts
useUserApi.ts
import { useHttpMethodContext } from '../../context/HttpMethodProvider';
import { ApiResponseData } from '../../types/api';
const useUserApi = () => {
const { get } = useHttpMethodContext();
const getAllUser = async (showApiLoader = true): Promise<ApiResponseData> => {
const response = await get('/user', showApiLoader);
// Add a parser if required
return response;
};
// other APIs related to users
return { getAllUser };
};
export default useUserApi;
Pages
src/
โโโ pages/
โ โโโ home/
โ โ โโโ Home.tsx
โ โโโ user/
โ โ โโโ UserDetails.tsx
Config
src/
โโโ config/
โ โโโ env.config.ts
Example of env.config.ts
export default {
API_URL: import.meta.env.VITE_API_URL,
APP_ENVIRONMENT: import.meta.env.VITE_APP_ENVIRONMENT || 'dev'
};
Step 4: Conclusion
With this, I conclude this tutorial. Let me know what you guys think about it and share your thoughts in the comment section.
Subscribe to my newsletter
Read articles from karan siddhu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by