---
title: Cele mai bune practici
---

Acest document prezintă cele mai bune practici pe care ar trebui să le urmați atunci când lucrați la frontend.

## Managementul stării

React și Recoil se ocupă de managementul stării în cod.

### Folosiți `useRecoilState` pentru a stoca starea

Este o bună practică să creezi atâția atomi câți ai nevoie pentru a-ți stoca starea.

<Warning>
  Este mai bine să folosești atomi suplimentari decât să încerci să fii prea concis recurgând la prop drilling.
</Warning>

```tsx
export const myAtomState = atom({
  key: 'myAtomState',
  default: 'default value',
});

export const MyComponent = () => {
  const [myAtom, setMyAtom] = useRecoilState(myAtomState);

  return (
    <div>
      <input
        value={myAtom}
        onChange={(e) => setMyAtom(e.target.value)}
      />
    </div>
  );
}
```

### Nu folosiți `useRef` pentru a stoca starea

Evitați utilizarea `useRef` pentru a stoca starea.

Dacă doriți să stocați starea, ar trebui să folosiți `useState` sau `useRecoilState`.

Vezi [cum să gestionezi re-randările](#managing-re-renders) dacă ți se pare că ai nevoie de `useRef` pentru a preveni apariția unor re-randări.

## Gestionarea re-randărilor

Re-render-urile pot fi greu de gestionat în React.

Aici sunt câteva reguli de urmat pentru a evita re-render-urile inutile.

Ține minte că poți **întotdeauna** evita re-randările înțelegând cauza lor.

### Lucrați la nivelul rădăcinii

Evitarea re-randărilor în funcționalități noi este acum ușoară prin eliminarea lor de la rădăcină.

Componenta secundară `PageChangeEffect` conține doar un `useEffect` ce deține toată logica de execuție la o schimbare de pagină.

În acest fel știți că există doar un loc care poate declanșa un re-render.

### Gândiți-vă de două ori înainte de a adăuga `useEffect` în baza de cod

Re-render-urile sunt adesea cauzate de `useEffect` inutile.

Ar trebui să vă gândiți dacă aveți nevoie de `useEffect` sau dacă puteți muta logica într-o funcție de handler de eveniment.

Vă va fi, în general, ușor să mutați logica într-o funcție `handleClick` sau `handleChange`.

De asemenea, le puteți găsi în biblioteci precum Apollo: `onCompleted`, `onError`, etc.

### Folosiți o componentă adiacentă pentru a extrage `useEffect` sau logica de interogare de date

Dacă simțiți nevoia să adăugați un `useEffect` în componenta rădăcină, ar trebui să luați în considerare extragerea sa într-o componentă secundară.

Puteți aplica același principiu pentru logica de interogare de date, folosind hooks cu Apollo.

```tsx
// ❌ Greșit, va provoca re-randări chiar dacă datele nu se schimbă,
//    deoarece useEffect trebuie re-evaluat
export const PageComponent = () => {
  const [data, setData] = useRecoilState(dataState);
  const [someDependency] = useRecoilState(someDependencyState);

  useEffect(() => {
    if(someDependency !== data) {
      setData(someDependency);
    }
  }, [someDependency]);

  return <div>{data}</div>;
};

export const App = () => (
  <RecoilRoot>
    <PageComponent />
  </RecoilRoot>
);
```

```tsx
// ✅ Bun, nu va provoca re-randări dacă datele nu se schimbă,
//   deoarece useEffect este re-evaluat într-o altă componentă la același nivel
export const PageComponent = () => {
  const [data, setData] = useRecoilState(dataState);

  return <div>{data}</div>;
};

export const PageData = () => {
  const [data, setData] = useRecoilState(dataState);
  const [someDependency] = useRecoilState(someDependencyState);

  useEffect(() => {
    if(someDependency !== data) {
      setData(someDependency);
    }
  }, [someDependency]);

  return <></>;
};

export const App = () => (
  <RecoilRoot>
    <PageData />
    <PageComponent />
  </RecoilRoot>
);
```

### Folosiți stări de familie și selectoare de familie cu recoil

Stările și selectoarele de familie cu recoil sunt o metodă excelentă de a evita re-render-urile.

Sunt utile când trebuie să stocați o listă de elemente.

### Nu ar trebui să folosiți `React.memo(MyComponent)`

Evitați utilizarea `React.memo()` deoarece nu rezolvă cauza re-render-ului, ci întrerupe lanțul re-render, ceea ce poate duce la comportamente neașteptate și face codul foarte greu de refactorizat.

### Limitați utilizarea `useCallback` sau `useMemo`

Acestea sunt adesea inutile și vor face codul mai greu de citit și menținut pentru un câștig în performanță care nu este sesizabil.

## Console.logs

Instrucțiunile `console.log` sunt valoroase în timpul dezvoltării, oferind informații în timp real despre valorile variabilelor și fluxul de cod. Totuși, lăsându-le în codul de producție pot duce la mai multe probleme:

1. **Performanță**: Logările excesive pot afecta performanța de execuție, în special în aplicațiile pe partea de client.

2. **Siguranță**: Logarea datelor sensibile poate expune informații critice oricui inspectează consola browser-ului.

3. **Claritate**: Umplerea consolei cu logări poate ascunde avertismente sau erori importante pe care dezvoltatorii sau uneltele le trebuie să le vadă.

4. **Profesionalism**: Utilizatorii finali sau clienții care verifică consola și văd o multitudine de instrucțiuni de log s-ar putea să pună la îndoială calitatea și finisajul codului.

Asigurați-vă că eliminați toate `console.log`-urile înainte de a trimite codul în producție.

## Denumiri

### Denumire de variabilă

Denumirile variabilelor trebuie să descrie cu precizie scopul sau funcția variabilei.

#### Problema cu denumirile generice

Denumirile generice în programare nu sunt ideale deoarece nu au specificitate, ducând la ambiguitate și la reducerea lizibilității codului. Astfel de denumiri nu reușesc să transmită scopul variabilei sau funcției, ceea ce îngreunează înțelegerea intenției codului de către dezvoltatori fără o investigație mai profundă. Acest lucru poate duce la creșterea timpului de depanare, la o mai mare susceptibilitate la erori și dificultăți în întreținere și colaborare. Între timp, denumirile descriptive fac codul auto-explicativ și mai ușor de navigat, îmbunătățind calitatea codului și productivitatea dezvoltatorilor.

```tsx
// ❌ Greșit, folosește un nume generic care nu îi comunică
//    clar scopul sau conținutul
const [value, setValue] = useState('');
```

```tsx
// ✅ Bun, folosește un nume descriptiv
const [email, setEmail] = useState('');
```

#### Câteva cuvinte de evitat în denumirile de variabile

* dummy

### Handlere de evenimente

Numele handlerelor de evenimente ar trebui să înceapă cu `handle`, în timp ce `on` este un prefix folosit pentru a denumi evenimentele în prop-urile componentelor.

```tsx
// ❌ Greșit
const onEmailChange = (val: string) => {
  // ...
};
```

```tsx
// ✅ Bun
const handleEmailChange = (val: string) => {
  // ...
};
```

## Props opționale

Evitați să transmiteți valoarea implicită pentru un props opțional.

**EXEMPLU**

Țineți cont de componenta `EmailField` definită mai jos:

```tsx
type EmailFieldProps = {
  value: string;
  disabled?: boolean;
};

const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
  <TextInput value={value} disabled={disabled} fullWidth />
);
```

**Utilizare**

```tsx
// ❌ Greșit, transmiterea aceleiași valori ca valoarea implicită nu aduce niciun beneficiu
const Form = () => <EmailField value="username@email.com" disabled={false} />;
```

```tsx
// ✅ Bun, presupune valoarea implicită
const Form = () => <EmailField value="username@email.com" />;
```

## Componentă ca props

Încercați, pe cât posibil, să transmiteți componente neinstanțiate ca props, astfel încât copiii să poată decide singuri de ce props au nevoie să transmită.

Cel mai frecvent exemplu pentru aceasta sunt componentele de pictograme:

```tsx
const SomeParentComponent = () => <MyComponent Icon={MyIcon} />;

// În MyComponent
const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => {
  const theme = useTheme();

  return (
    <div>
      <MyIcon size={theme.icon.size.md}>
    </div>
  )
};
```

Pentru ca React să înțeleagă că componenta este o componentă, trebuie să folosești PascalCase, pentru a o instanția ulterior cu `<MyIcon>`

## Prop Drilling: Păstrați-l Minimal

Prop drilling, în contextul React, se referă la practica de a transmite variabile de stare și setatorii acestora prin multe straturi de componente, chiar dacă componentele intermediare nu le folosesc. Deși uneori necesar, prop drilling excesiv poate duce la:

1. **Citibilitate Scăzută**: Urmărirea de unde provine un prop sau unde este utilizat poate deveni complexă într-o structură de componente foarte profundă.

2. **Provocări de Mentenanță**: Schimbările în structura props a unei componente pot necesita ajustări în mai multe componente, chiar dacă acestea nu utilizează direct prop-ul.

3. **Reutilizabilitate Redusă a Componentelor**: O componentă ce primește multe props doar pentru a le transmite mai departe devine mai puțin de uz general și mai greu de reutilizat în contexte diferite.

Dacă simțiți că folosiți prea mult prop drilling, consultați [cele mai bune practici de gestionare a stării](#state-management).

## Importuri

Când importați, optați pentru pseudonimele desemnate în loc să specificați căi complete sau relative.

**Pseudonimele**

```js
{
  alias: {
    "~": path.resolve(__dirname, "src"),
    "@": path.resolve(__dirname, "src/modules"),
    "@testing": path.resolve(__dirname, "src/testing"),
  },
}
```

**Utilizare**

```tsx
// ❌ Greșit, specifică întreaga cale relativă
import {
  CatalogDecorator
} from '../../../../../testing/decorators/CatalogDecorator';
import {
  ComponentDecorator
} from '../../../../../testing/decorators/ComponentDecorator';
```

```tsx
// ✅ Bun, utilizează aliasurile stabilite
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from 'twenty-ui/testing';
```

## Validarea Schemelor

[Zod](https://github.com/colinhacks/zod) este validatorul de scheme pentru obiectele netipizate:

```js
const validationSchema = z
  .object({
    exist: z.boolean(),
    email: z
      .string()
      .email('Adresa de email trebuie să fie validă'),
    password: z
      .string()
      .regex(PASSWORD_REGEX, 'Parola trebuie să conțină cel puțin 8 caractere'),
  })
  .required();

type Form = z.infer<typeof validationSchema>;
```

## Schimbări Majore

Efectuați întotdeauna teste manuale temeinice înainte de a continua pentru a garanta că modificările nu au cauzat întreruperi în altă parte, având în vedere că testele nu au fost încă integrate extensiv.
