-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix: [Section] Scalable Application Structure #323
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,226 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Scalable Application Structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Creating a scalable structure for a React-Redux application is crucial for long-term maintainability, team collaboration, and feature evolution. This section outlines a strategy focused on **feature-based architecture**, enabling you to group files by domain, easily add or remove features, toggle them on demand, and ensure reusability across different projects. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Core Goals | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 1. **Feature-First Organization**: Group all related code (components, actions, reducers, selectors, types) by feature rather than by file type. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 2. **Modularity**: Make features self-contained units that can be added or removed with minimal impact on the rest of the application. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 3. **Dynamic Feature Toggling**: Enable or disable features at runtime or build time without refactoring core logic. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 4. **Reusability & Pluggability**: Design features as independent packages or modules that can be dropped into different Redux applications. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Recommended Directory Structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Instead of the traditional `actions/`, `components/`, `reducers/` folders at the root, organize your `src` directory by **features**. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| src/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ├── app/ # App-level configuration, providers, global styles | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── store.ts # Redux store configuration | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── App.tsx # Root component | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ └── index.tsx # Entry point | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ├── features/ # Feature modules | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── auth/ # Authentication feature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── components/ # Auth-specific components | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── slices/ # Redux Toolkit slice (actions + reducer) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── hooks.ts # Custom hooks for this feature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── selectors.ts # Feature-specific selectors | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── types.ts # TypeScript interfaces/types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ └── index.ts # Public API (exports only what's needed) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── dashboard/ # Dashboard feature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── components/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── slices/ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── hooks.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── selectors.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ ├── types.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ │ └── index.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ └── settings/ # Settings feature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ └── ... | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ├── shared/ # Shared utilities, UI components, types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── components/ # Generic UI components (Button, Modal) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── hooks/ # Generic hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ ├── utils/ # Helper functions | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| │ └── types.ts # Global types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| └── config/ # Environment variables, feature flags | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| └── featureFlags.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Implementation Details | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 1. Feature Modules as Self-Contained Units | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Each feature in `src/features/` should be a complete unit. It should contain its own Redux slice, components, and types. This isolation ensures that changes to one feature rarely break another. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Example: `features/auth/slices/authSlice.ts`** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { createSlice, PayloadAction } from '@reduxjs/toolkit'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| interface AuthState { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user: string | null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isAuthenticated: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loading: boolean; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const initialState: AuthState = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| user: null, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| isAuthenticated: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loading: false, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const authSlice = createSlice({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: 'auth', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| initialState, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reducers: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginStart: (state) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.loading = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginSuccess: (state, action: PayloadAction<string>) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.user = action.payload; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.isAuthenticated = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.loading = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| loginFailure: (state) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.loading = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logout: (state) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.user = null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| state.isAuthenticated = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const { loginStart, loginSuccess, loginFailure, logout } = authSlice.actions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default authSlice.reducer; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Example: `features/auth/index.ts` (Public API)** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Only export what external parts of the app need | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { default as authReducer } from './slices/authSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { loginStart, loginSuccess, loginFailure, logout } from './slices/authSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { useAuth } from './hooks'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { selectUser, selectIsAuthenticated } from './selectors'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type { AuthState } from './types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 2. Enabling/Disabling Features on Demand | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| To enable dynamic feature toggling, use a configuration file and conditional rendering or conditional store injection. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **`src/config/featureFlags.ts`** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const FEATURE_FLAGS = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| AUTH: process.env.REACT_APP_ENABLE_AUTH === 'true', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DASHBOARD: process.env.REACT_APP_ENABLE_DASHBOARD === 'true', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| SETTINGS: process.env.REACT_APP_ENABLE_SETTINGS === 'true', | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Conditional Store Injection** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| When configuring your Redux store, only include reducers for enabled features. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // src/app/store.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { configureStore } from '@reduxjs/toolkit'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FEATURE_FLAGS } from '../config/featureFlags'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Import reducers conditionally | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import authReducer from '../features/auth/slices/authSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import dashboardReducer from '../features/dashboard/slices/dashboardSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import settingsReducer from '../features/settings/slices/settingsSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const reducer = { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(FEATURE_FLAGS.AUTH && { auth: authReducer }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(FEATURE_FLAGS.DASHBOARD && { dashboard: dashboardReducer }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ...(FEATURE_FLAGS.SETTINGS && { settings: settingsReducer }), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+136
to
+140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Issues with Conditional Store InjectionConditionally injecting reducers using object spreading can lead to runtime and type-safety issues:
Recommended Alternatives:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const store = configureStore({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reducer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type RootState = ReturnType<typeof store.getState>; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type AppDispatch = typeof store.dispatch; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Conditional Component Rendering** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| In your main `App.tsx`, only render feature components if the flag is active. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // src/app/App.tsx | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { FEATURE_FLAGS } from '../config/featureFlags'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { AuthPage } from '../features/auth/components/AuthPage'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Dashboard } from '../features/dashboard/components/Dashboard'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Settings } from '../features/settings/components/Settings'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function App() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {FEATURE_FLAGS.AUTH && <AuthPage />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {FEATURE_FLAGS.DASHBOARD && <Dashboard />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {FEATURE_FLAGS.SETTINGS && <Settings />} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </div> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+156
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Public API Violation & Lack of Code SplittingThere are two main architectural issues with this implementation:
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export default App; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ### 3. Reusability and Pluggability | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| To make features reusable across different applications: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Package as a Library**: Extract a feature into a separate npm package. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Use TypeScript Interfaces**: Define clear contracts for props and state. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Avoid Hard Dependencies**: Do not import from other features directly. Use dependency injection or context if cross-feature communication is needed. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Export a Clean API**: Ensure the `index.ts` of each feature exports only the necessary components, hooks, and types. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| **Example: Exporting a Feature as a Reusable Module** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // features/auth/index.ts | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { AuthProvider, useAuth } from './components/AuthProvider'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export { authReducer } from './slices/authSlice'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export type { AuthState, AuthActions } from './types'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Another application can then install this feature as a dependency: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```bash | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| npm install @myapp/auth-feature | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| And use it: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ```typescript | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { AuthProvider, authReducer } from '@myapp/auth-feature'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // In store config | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const store = configureStore({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| reducer: { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| auth: authReducer, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // ... other reducers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // In App | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <AuthProvider> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| <App /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| </AuthProvider> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ``` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Benefits of This Structure | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Scalability**: As the app grows, new features are added without cluttering the root directory. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Maintainability**: Developers can work on a single feature without worrying about breaking others. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Flexibility**: Features can be toggled on/off via environment variables or runtime flags. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| - **Reusability**: Features can be extracted and reused in other projects with minimal changes. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ## Conclusion | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Adopting a feature-based, scalable structure in your React-Redux TypeScript application ensures that your codebase remains clean, modular, and adaptable. By grouping files by feature, enabling dynamic toggling, and designing for reusability, you create a foundation that can grow with your project and team. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Public API Violation
Importing directly from internal paths like
../features/auth/slices/authSlicebypasses the feature's public API (index.ts). This violates the encapsulation and modularity goals described earlier in the guide.To maintain strict boundaries, always import from the feature's root entry point.