Folder structure for pure redux
The simplest way is to grouped by logical components, such as action creators, selectors, etc
Considering the collaboration and TDD, some components are highly recommended to share across projects. Below illustrates the dependency
* indicates the components requiring unit test, for those with double stars, we will mention that in redux master
Suggested location for project-based and inter-project-sharing modules
Assume that we demand the MobApp and WebApp sharing similar business logic, below snapshot shows the suggested location of individual module
./app
/constants
/ApplePay.js
/index.js
/actions
/ApplePay.js
/index.js
/components
/Profile
/_Layout.js
/StudentProfile.js
/TeacherProfile.js
/AutodetectProfile.js
/containers.js
/index.js
/configs
/prod.js
/beta.js
/index.js
/l10n
/images
/[email protected]
/[email protected]
/[email protected]
/[email protected]
/[email protected]
/[email protected]
/index.js (RN only)
/translations
/en-HK
/AccountViewer.json
/ProfileBrowser.json
/images.json (RJ only)
/common.json
/zh-HK
/AccountViewer.json
/ProfileBrowser.json
/images.json (RJ only)
/common.json
/reducers
/ApplePay.js
/index.js
/routes
/AccountViewer.js
/ProfileBrowser.js
/sagas
/ApplePay.js
/index.js
/selectors
/ApplePay.js
/index.js
/services
/axios_translation.js
/apple_pay.js
/android_pay.js
/navigation.js
/tracking.js
/db_storage.js
/tests
/graceful_disconnect.js
/App.js
/i18n.js
/index.js
/store.js
./common
/constants
/AccountViewer.js
/ProfileBrowser.js
/actions
/AccountViewer.js
/ProfileBrowser.js
/containers
/AccountViewer.js
/ProfileBrowser.js
/reducers
/AccountViewer.js
/ProfileBrowser.js
/sagas
/AccountViewer.js
/ProfileBrowser.js
/selectors
/AccountViewer.js
/ProfileBrowser.js
/services
/axios_catalog.js
/axios_session.js
/axios_user.js
/store
/_configureStore.js
/tests
/rootReducer.js
/rootSaga.js
Module | Project-based | Shareable over projects |
---|---|---|
Actions | ./app/constants/ | ./common/constants/${Scene}.js |
Action creators | ./app/actions/ | ./common/actions/${Scene}.js |
Components | ./app/components/${Component}/ | - |
Configs | ./app/configs/${stage_name} | - |
Containers including shared connecters, translators, etc | ./app/components/${Component}/containers.js | ./common/containers/${Scene}.js |
Internationalisation agent | ./app/i18n.js | |
Localisation | ./app/l10n/index.js | - |
Localised images | ./app/l10n/images/ | - |
Localised translations | ./app/l10n/translations/ | - |
Providers and root application | ./app/App.js | - |
Reducers | ./app/reducers/ | ./common/reducers/${Scene}.js |
Router - sub router | ./app/routes/${RouterName}.js | |
Router - root router # | ./app/index.js | |
Sagas | ./app/sagas/ | ./common/sagas/${Scene}.js |
Sagas: HOF for saga | - | ./common/sagas/_${Scene}.js |
Selectors | ./app/selectors/ | ./common/selectors/${Scene}.js |
Services | ./app/services/ | ./common/services/ |
Service for navigation | ./app/services/navigation.js | - |
Service for tracking | ./app/services/tracking.js | - |
Service for data base | ./app/services/data_base.js | - |
Store | ./app/store.js | - |
Store: HOF for configureStore | - | ./common/store/_configureStore.js |
Tests | ./app/tests/ | ./common/tests/${nature}.js |
Design principle: Writing common library for collaborative project
Always use ./common or ./shared or ./vendor for submodule offered to project whenever we have logical modules reused over projects.
// ./common/selectors/AccountViewer.js
export const is_logined = (state) => state.AccountViewer.email && state.AccountViewer.authorization_bearer;
// ./common/selectors/CartCheckout.js
export const is_ready_to_proceed = createSelector(
is_over_min_pay,
is_not_over_weight,
is_terms_and_condition_accepted,
(is_over_min_pay, is_not_over_weight, is_terms_and_condition_accepted) =>
is_over_min_pay && is_not_over_weight && is_terms_and_condition_accepted
)
// ./common/selectors/index.js
export * from './AccountViewer';
export * from './CartCheckout';
Yet, you are advised to
- keep ./shared for monolithic application #
- keep ./lib for LOA
Design principle: Aggregation in ./app/*/index.js
Always use index.js for single point of import. To do this, say we have tons of selectors written in separated files, you can write a little index.js for aggregation.
// ./app/selectors/index.js
export * from './cart';
export * from './account';
export * from './daypass';
Furthermore, always import to corresponding folder of shared logical components in project ./app level prior to further import. And if necessary, you may add project-level selectors
// ./app/selectors/QRCodeScanner.js
export const is_camera_available = (state) => !!state.system.camera;
// ./app/selectors/BrowserChecking.js
export const is_bookmark_available = (state) => !!state.system.bookmark;
// ./app/selectors/index.js
export * from '../../common/selectors';
export * from './QRCodeScanner';
export * from './BrowserChecking';
# In monolithic redux application, scene ( or Screen or Flow ) -based folder structure would be a superior strategy to manage sophisticated structure.
For detail, please refer to The masters > Scene