Segment
The third level of application partitioning, according to the purpose of the module in the code and implementation
{layer}/
โโโ {slice}/
| โโโ ui/ # UI-logic (components, ui-widgets, ...)
| โโโ model/ # Business logic (store, actions, effects, reducers, ...)
| โโโ lib/ # Infrastructure logic (utils/helpers)
| โโโ config/ # Application configuration (env-vars, ...)
| โโโ api/ # Logic of API requests (api instances, requests, ...)
General rulesโ
Each of the above segments represents the levels of abstractions that are familiar to us when developing software.
Each of the segments is responsible for its own scope, but all together - they form a single image of this slice and its logic, specifically:
- its visual display (ui)
- its business logic (model)
- its auxiliary modules (lib)
Also, in rare cases, affecting:
- its configuration (config)
- its logic for working with API requests (api)
Each segment can be either a file or a directory - it depends on the complexity of the slice being implemented
That is, such options are also quite acceptable:
features/wallet/add-funds
โโโ ui.tsx
โโโ model.ts
โโโ index.ts
pages/home/
โโโ index.tsx
โโโ style.module.scss
ui
โ
UI representation of the module
It can contain inside:
- Components of your UI framework (React, Vue, Angular, ...)
- Canvas-Widgets
- (any other ui view modules)
Examplesโ
Complex UI for the layerโ
{layer}/{slice}/
โโโ ui/
| โโโ toolbar/
| | โโโ title/
| | โโโ actions/
| โโโ content/
| | โโโ sort/
| | โโโ table/
| โโโ index.tsx
| โโโ styles.module.scss
import { Layout } from "shared/ui";
import Toolbar from "./toolbar";
import Content from "./content";
import styles from "./styles.module.scss";
export const SomeForm = () => (
<Layout className={styles.root}>
<Toolbar className={styles.toolbar} />
<Content className={styles.content} />
</Layout>
);
model
โ
Business logic of the module
May contain:
- The logic of creating and updating a mini-store for this slice
- In the effector world:
createStore
+createDomain
- In the redux world:
createSlice
- In the effector world:
- A list of events processed by the parent slice model and updating its state
- In the effector world:
events
- In the redux world:
actions
+dispatch
- In the effector world:
- List of asynchronous side effects, for loading data and other asynchronous operations
- In the effector world:
effects
- In the redux world:
thunks
/sagas
/epics
- In the effector world:
- List of selectors/contracts/hooks for using the slice state
- In the effector world:
useStore
, ... - In the redux world:
useSelector
,selectors
- In the effector world:
lib
โ
Auxiliary libraries
It usually contains a set of utilities that help writing logic and are distributed in groups, i.e. separate libraries.
api
โ
Logic of interaction with the API
Usually contains
- instances for working with different external APIs
- methods / factories for calling specific endpoints
In rare cases (react-query / graphql), the queries themselves may lie near the place of use
- But most often recommended place the API segment in the 'shared' layer to reduce the number of logic entanglements
At the same time, this segment can be written manually or generated using the API scheme
- For example, using
openapi-generator
,swagger-codegen
Examplesโ
export class UserApi {
constructor(config) {...}
getList(params: GetListParams): Promise<User[]> {...}
...
}
import { userApi } from "shared/api"
// API instances can be created
// both at the place of use and in the API segment itself
//
// const userApi = new UserApi();
export const getUserListThunk = createAsyncThunk("...", (params) => {
return userApi.getList(params);
});
config
โ
Application configuration module and its environment
It usually contains the application configuration and methods for working with it
Examplesโ
Using environment variablesโ
The implementation depends on the project and the team, here is just one of the options
export const isDevEnv = NODE_ENV === "development";
export const OAUTH_TOKEN = getEnvVar("REACT_APP_OAUTH_TOKEN");
import { OAUTH_TOKEN, isDevEnv } from "shared/config";
export const OAuthProvider = () => (
<OAuth
debug={isDevEnv}
token={OAUTH_TOKEN}
...
/>
)
See alsoโ
WIP:
Over time, articles on each abstraction will appear