Appearance
Best Practices
Error Handling
- Use
@uni-ts/resultto handle expected errors and throw the unexpected ones. - Use
Sentry.captureExceptionorSentry.captureMessagefor unexpected errors. - Read
@uni-ts/resultdocs to understand its usage patterns and best practices.
Data Modeling
- Use
@uni-ts/modelto define data models. Read the docs to understand its usage patterns and best practices. - Import all model-related utils from
@/common/helpers/models. - When writing any logic that uses models, prefer assigning this logic to the model itself.
Business Logic Gradation
To keep the project maintainable we want to keep business logic as close to the data (and as far from the UI) as possible. To make this simple, use the following gradation:
- Data structure - just a constant holding some data. If validation is needed, make it a model.
- Pure function - function returning the same output for the same input.
- Action function - function using some external state (e.g. localStorage).
- Hook - function using some react utilities (other hooks).
- Component - function that renders UI.
Choose the lowest gradation
Whenever you can move the logic (or its part) to the lower gradation without affecting project's complexity, do it. It's far easier to combine logic together if needed than to split it apart.
Dialogs
To mitigate the coupling between dialogs and components that need to use them we use DialogProvider with accompanied hooks. There are a few steps to follow if you want to create a new dialog:
- Use
createDialogStoreto create a new store for dialog data. You can pass the data required by the dialog as the generic type.
ts
const SampleDialogStore = createDialogStore<{ message: string }>();- Create the dialog component and pass the
useDialogPropsas its props.
jsx
function SampleDialog() {
return (
<Dialog {...useDialogProps(SampleDialogStore)}>
<SampleDialogContent />
</Dialog>
);
}- Use
DialogProviderto allow all descendants to use the dialog.
jsx
<DialogProvider component={SampleDialog} store={SampleDialogStore}>
{children}
</DialogProvider>- You can access the dialog data using
useDialogDatahook. If you're sure that the dialog is open (e.g. you're inside the dialog component), you can useuseDialogDataOrThrow.
jsx
function SampleDialogContent() {
const { message } = useDialogDataOrThrow(SampleDialogStore);
return <div>{message}</div>;
}- To control the dialog, use the
useDialogActionshook.
jsx
function CloseDialogButton() {
const { close } = useDialogActions(SampleDialogStore);
return <Button onClick={close}>Close Dialog</Button>;
}