When it comes to developing a React application, maintaining an organized project structure is key to keeping your codebase clean, scalable, and easy to work with. In this blog, we'll explore a well-organized React project structure and understand the purpose of each folder.
Here's the folder structure you've adopted for your React project:
src
-> components
-> Dashboard.js
-> Header.js
-> Transaction.js
-> context
-> MainContext.js
-> hooks
-> GetData.js
-> reducer
-> MainReducer.js
-> App.js
Now, let's dive into each of these folders:
The components folder is the home for your React components. It's a good practice to keep your components organized in one place to make them easily accessible and reusable. This folder contains components like Dashboard, Header, and Transaction.
import { Col, Card } from 'react-bootstrap'
import { useGetData } from '../hooks/GetData';
const Dashboard = () => {
const data = useGetData()
return (
<>
<Col>
<Card>
<Card.Body>
<Card.Title>INCOME</Card.Title>
<Card.Title><b>${data.income.toFixed(2)}</b></Card.Title>
</Card.Body>
</Card>
</Col>
<Col>
<Card>
<Card.Body>
<Card.Title>EXPANSE</Card.Title>
<Card.Title><b>${data.expanse.toFixed(2)}</b></Card.Title>
</Card.Body>
</Card>
</Col>
</>
)
}
export default Dashboard;
import { useContext } from "react";
import { useGetData } from "../hooks/GetData";
const Header = () => {
const data = useGetData()
return (
<>
<h2>Simple Expance Tracker</h2>
<br />
<h4>Your Balance</h4>
<h2>$ {data.balance.toFixed(2)}</h2>
</>
)
}
export default Header;
import { Table } from "react-bootstrap";
const Transaction = ({ data }) => {
return (
<>
<h3 className='mt-3'>History</h3>
<Table bordered>
<thead>
<tr>
<th>#</th>
<th>Description</th>
<th>Type</th>
<th>Amount</th>
</tr>
</thead>
<tbody>
{
data.history.length > 0 ?
data.history.map((single, index) =>
(<tr key={index}>
<td>{index + 1}</td>
<td>{single.description}</td>
<td>{single.type}</td>
<td>{single.amount}</td>
</tr>)
) : (<tr><td colSpan={4} className='text-center'>Transaction Not Found...</td></tr>)}
</tbody>
</Table>
</>
)
}
export default Transaction;
The context folder is where you manage application-wide state and data. In React, the Context API is a powerful tool for managing state across your components. Your MainContext.js file likely contains the context provider and any related logic for sharing state.
import { createContext } from "react";
const initialState = {
'balance': 0.00,
'income': 0.00,
'expanse': 0.00,
'history': []
}
const MainContext = createContext(initialState)
export default MainContext;
React hooks are a great way to share reusable behavior between components. The hooks folder holds custom hooks that can be used in multiple parts of your application. For example, GetData.js might be a custom hook that fetches data from an API.
import { useContext } from "react"
import MainContext from "../context/MainContext"
export function useGetData() {
return useContext(MainContext)
}
The reducer folder is home to your application's reducers, primarily used with the Context API or Redux. Your MainReducer.js file likely contains the logic for managing state changes in response to various actions.
const mainReducer = (state, action) => {
switch (action.type) {
case 'add-income':
return { ...state, history: [...state.history, action.payload.history], income: action.payload.income, balance: action.payload.balance }
case 'add-expanse':
return { ...state, history: [...state.history, action.payload.history], expanse: action.payload.expanse, balance: action.payload.balance }
default:
return state;
}
}
export default mainReducer;
The App.js file serves as the entry point of your application. It's the root component that houses the main structure of your app and may include routing or other global configurations.
import { useContext, useReducer, useState } from 'react';
import { Button, Card, Col, Container, Row, Modal, Form } from 'react-bootstrap';
import mainReducer from './reducer/MainReducer';
import Header from './components/Header';
import Dashboard from './components/Dashboard';
import Transaction from './components/Transaction';
import MainContext from './context/MainContext';
import AddButton from './components/AddButton'
function IncomeExpanseApp() {
const [show, setShow] = useState(false);
const [showExpanse, setShowExpanse] = useState(false);
const handleClose = () => setShow(false);
const handleShow = () => setShow(true);
const handleCloseExpanse = () => setShowExpanse(false);
const handleShowExpanse = () => setShowExpanse(true);
const initialTransaction = { 'description': '', 'amount': 0.00 }
const [getTransaction, setTransaction] = useState(initialTransaction)
const contextdata = useContext(MainContext)
const [data, dispatch] = useReducer(mainReducer, contextdata);
const hanleIncomeTransaction = () => {
let oldIncome = data.income;
let newIncome = oldIncome += parseFloat(getTransaction.amount);
let oldBalance = data.balance;
let newBalance = oldBalance + parseFsloat(getTransaction.amount);
let payload = { 'income': parseFloat(newIncome), 'history': getTransaction, 'balance': newBalance }
dispatch({ type: 'add-income', payload: payload })
setTransaction(initialTransaction);
setShow(false);
}
const hanleExpanseTransaction = () => {
let oldExpanse = data.expanse;
let newExpanse = oldExpanse += parseFloat(getTransaction.amount);
let oldBalance = data.balance;
let newBalance = oldBalance - parseFloat(getTransaction.amount);
let payload = { 'expanse': parseFloat(newExpanse), 'history': getTransaction, 'balance': newBalance }
dispatch({ type: 'add-expanse', payload: payload })
setTransaction(initialTransaction);
setShowExpanse(false);
}
return (
<>
<MainContext.Provider value={data}>
<Container className='text-center'>
<Header />
<Row>
<Dashboard />
<Col>
<AddButton handleShow={handleShow} handleShowExpanse={handleShowExpanse} />
</Col>
</Row>
<Transaction data={data} />
</Container>
<Modal show={show} onHide={handleClose}>
<Modal.Header closeButton>
<Modal.Title>Add Income</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Description</Form.Label>
<Form.Control type="text" placeholder="Enter income description" onKeyUp={(e) => setTransaction({ ...getTransaction, description: e.target.value })} defaultValue={getTransaction.description} />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Amount</Form.Label>
<Form.Control type="number" placeholder="Enter Amount" onKeyUp={(e) => setTransaction({ ...getTransaction, amount: e.target.value, type: 'Cr' })} defaultValue={getTransaction.amount} />
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleClose}>
Close
</Button>
<Button variant="primary" onClick={hanleIncomeTransaction}>
Add Transaction
</Button>
</Modal.Footer>
</Modal>
<Modal show={showExpanse} onHide={handleCloseExpanse}>
<Modal.Header closeButton>
<Modal.Title>Add Expanse</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Group className="mb-3" controlId="formBasicEmail">
<Form.Label>Description</Form.Label>
<Form.Control type="text" placeholder="Enter income description" onKeyUp={(e) => setTransaction({ ...getTransaction, description: e.target.value })} defaultValue={getTransaction.description} />
</Form.Group>
<Form.Group className="mb-3" controlId="formBasicPassword">
<Form.Label>Amount</Form.Label>
<Form.Control type="number" placeholder="Enter Amount" onKeyUp={(e) => setTransaction({ ...getTransaction, amount: e.target.value, type: 'Dr' })} defaultValue={getTransaction.amount} />
</Form.Group>
</Form>
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={handleCloseExpanse}>
Close
</Button>
<Button variant="primary" onClick={hanleExpanseTransaction}>
Add Transaction
</Button>
</Modal.Footer>
</Modal>
</MainContext.Provider>
</>
);
}
export default IncomeExpanseApp;
Organizing your project in this way provides several advantages:
Maintainability: With a clear folder structure, it's easier to find and modify code. This is particularly helpful when working on large projects with multiple team members.
Reusability: Placing components in the components folder allows you to reuse them in different parts of your application.
Separation of Concerns: Dividing your code into folders based on functionality makes it clear which parts of your project handle specific tasks.
Scalability: As your project grows, this structure makes it easier to add new features and components without introducing chaos.
An organized folder structure is a fundamental aspect of good software development. The structure you've chosen for your React project is well-organized, promotes code reusability, and simplifies maintenance. By following this structure, you'll have a strong foundation for building a scalable and maintainable application.
My name is Deepak tailor as a fullstack developer. I have been in the IT industry (PHP, Nodejs, flutter) for the last 5 years. For professional and customize web development & app development, you can send inquiry on our email.
----
You can contact him at deepaktailor10@yahoo.in