Skip to content

Best Practices

Error Handling

  • Use @uni-ts/result to handle expected errors and throw the unexpected ones.
  • Use Sentry.captureException or Sentry.captureMessage for unexpected errors.
  • Read @uni-ts/result docs to understand its usage patterns and best practices.

Data Modeling

  • Use @uni-ts/model to 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:

  1. Data structure - just a constant holding some data. If validation is needed, make it a model.
  2. Pure function - function returning the same output for the same input.
  3. Action function - function using some external state (e.g. localStorage).
  4. Hook - function using some react utilities (other hooks).
  5. 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:

  1. Use createDialogStore to 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 }>();
  1. Create the dialog component and pass the useDialogProps as its props.
jsx
function SampleDialog() {
  return (
    <Dialog {...useDialogProps(SampleDialogStore)}>
      <SampleDialogContent />
    </Dialog>
  );
}
  1. Use DialogProvider to allow all descendants to use the dialog.
jsx
<DialogProvider component={SampleDialog} store={SampleDialogStore}>
  {children}
</DialogProvider>
  1. You can access the dialog data using useDialogData hook. If you're sure that the dialog is open (e.g. you're inside the dialog component), you can use useDialogDataOrThrow.
jsx
function SampleDialogContent() {
  const { message } = useDialogDataOrThrow(SampleDialogStore);

  return <div>{message}</div>;
}
  1. To control the dialog, use the useDialogActions hook.
jsx
function CloseDialogButton() {
  const { close } = useDialogActions(SampleDialogStore);

  return <Button onClick={close}>Close Dialog</Button>;
}