Frontend State Management
Relevant source files
The following files were used as context for generating this wiki page:
The frontend application employs a hybrid state management strategy, combining React's Context API for global, cross-component state with local component state for UI logic and data handling within specific pages or components. This approach is outlined in the project structure, which designates a src/context/ directory for React Context state management.
The primary global states managed are user authentication (AuthContext) and application theme (ThemeContext). For more localized needs, components directly use React hooks like useState, useEffect, and useMemo to manage their internal state, such as user interactions, form inputs, and data derived for visualizations.
Sources: README.md, frontend/src/index.js:10-11
Global State via React Context
The application leverages the React Context API to provide global state to the entire component tree. This is configured in the main entry point, frontend/src/index.js, where the App component is wrapped with custom Provider components.
Sources: frontend/src/index.js:15-23
Provider Hierarchy
The AuthProvider and ThemeProvider are nested to make authentication and theme state available to all child components. The BrowserRouter wraps them all to enable routing capabilities.
This diagram illustrates the provider wrapping structure in index.js.
Sources: frontend/src/index.js:15-23
AuthProvider
The AuthProvider is responsible for managing the application's authentication state. While its internal implementation is not detailed in the provided files, its placement in index.js signifies its role in providing authentication data (e.g., current user, login status) and functions (e.g., login, logout) to the entire application. This context is consumed by protected route components like ProtectedRoute and RequireAdmin to control access to specific pages based on user authentication and roles.
Sources: frontend/src/index.js:17, frontend/src/App.js:31, 41
ThemeProvider
The ThemeProvider manages the application's visual theme (e.g., light or dark mode). Components can consume this context to adapt their styles accordingly.
Usage Example
The SidebarAdmin component uses the useTheme hook to get the current theme and apply conditional styling.
// frontend/src/components/common/SidebarAdmin.js:46-47
const SidebarAdmin = () => {
const { theme } = useTheme();
// ...
return (
// ...
<aside
className={`w-[216px] h-[700px] rounded-[25px] shadow relative flex flex-col transition-colors duration-300
${theme === "light" ? "bg-white text-black" : "bg-zinc-900 text-zinc-200"}`}
>
// ...
</aside>
// ...
);
};
Sources: frontend/src/components/common/SidebarAdmin.js:47, 80-82
The theme state directly influences the CSS classes applied to the main body element, allowing for global style changes via CSS.
/* frontend/src/index.css:8-12 */
/* Khi bật dark mode, tự đổi nền và màu chữ toàn ứng dụng */
.dark body {
@apply bg-zinc-900 text-zinc-100 transition-colors duration-300;
}
Sources: frontend/src/index.css:8-12
Local Component State
For state that is not needed globally, components manage their own state using React's built-in hooks. This is common for handling UI interactions, form data, and page-specific data fetching and display.
UI Interaction State
The Public_page component uses useState and useEffect to manage the active navigation item based on the user's scroll position.
useState: AnactiveItemstate variable is declared to track the currently visible section.useEffect: A scroll event listener is attached to the window. It uses a throttled handler to efficiently determine which section is in view and updates theactiveItemstate.
This flow chart shows how scrolling updates the UI state.
Data and Filter State
The AirQualityIndexPage component demonstrates how local state is used to manage user-selected filters and the data displayed in charts.
useState: Two state variables,metricKeyandrange, are used to store the user's selection from dropdown menus for the metric type (e.g., "PM2.5") and time range (e.g., "Real-time").useMemo: The chart data is recalculated usinguseMemo. This hook ensures that thegenDatafunction is only called whenmetricKeyorrangechanges, optimizing performance by avoiding unnecessary recalculations on every render.
The table below summarizes the state variables in this component.
| State Variable | Hook | Purpose |
|---|---|---|
metricKey | useState | Stores the currently selected air quality metric (e.g., 'PM25', 'CO2'). |
range | useState | Stores the selected time range for the chart (e.g., 'realtime', 'day'). |
metric | - | A derived constant holding configuration for the selected metricKey. |
data | useMemo | Memoized chart data that recalculates only when metricKey or range changes. |
current | - | The latest data point value, derived from the data array. |
Sources: frontend/src/pages/AirQualityIndexPage.jsx:168-172
This diagram illustrates the data flow when a user changes a filter.
Summary
The project's frontend state management is well-structured and pragmatic. It correctly separates global concerns from local ones.
- Global State:
AuthContextandThemeContextprovide application-wide state for authentication and theming, respectively. This is a clean and effective use of the React Context API. - Local State: Standard React hooks (
useState,useEffect,useMemo) are used within components to manage UI interactions and data transformations, ensuring that state is scoped as locally as possible. This improves component encapsulation and performance.
This hybrid approach is scalable and aligns with modern React development practices.