---
title: Najlepsze praktyki
image: /images/user-guide/tips/light-bulb.png
---

<Frame>
  <img src="/images/user-guide/tips/light-bulb.png" alt="Header" />
</Frame>

Ten dokument opisuje najlepsze praktyki, które powinieneś stosować podczas pracy nad frontendem.

## Zarządzanie stanem

React i Recoil obsługują zarządzanie stanem w kodzie.

### Użyj `useRecoilState` do przechowywania stanu

Dobrą praktyką jest tworzenie tylu atomów, ile potrzeba do przechowywania stanu.

<Warning>

Lepiej użyć dodatkowych atomów niż próbować być zbyt oszczędnym przy przekazywaniu atrybutów.

</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>
  );
}
```

### Nie używaj `useRef` do przechowywania stanu

Unikaj używania `useRef` do przechowywania stanu.

Jeśli chcesz przechowywać stan, powinieneś użyć `useState` lub `useRecoilState`.

Zobacz [jak zarządzać ponownymi renderowaniami](#managing-re-renders) jeśli czujesz, że potrzebujesz `useRef` do zapobiegania niektórym ponownym renderowaniom.

## Zarządzanie ponownymi renderowaniami

Ponowne renderowania mogą być trudne do zarządzania w React.

Oto kilka zasad do stosowania, aby unikać niepotrzebnych ponownych renderowań.

Pamiętaj, że możesz **zawsze** unikać ponownych renderowań poprzez zrozumienie ich przyczyny.

### Pracuj na poziomie korzenia

Unikanie ponownych renderowań w nowych funkcjach jest teraz łatwe dzięki eliminacji ich na poziomie korzenia.

Komponent boczny `PageChangeEffect` zawiera tylko jedno `useEffect`, które zawiera całą logikę do wykonania przy zmianie strony.

W ten sposób wiesz, że jest tylko jedno miejsce, które może wywołać ponowne renderowanie.

### Zawsze zastanów się dwa razy, zanim dodasz `useEffect` do swojego kodu

Ponowne renderowania są często powodowane przez niepotrzebne `useEffect`.

Powinieneś zastanowić się, czy potrzebujesz `useEffect`, czy możesz przenieść logikę do funkcji obsługującej zdarzenie.

Zazwyczaj łatwo jest przenieść logikę do funkcji `handleClick` lub `handleChange`.

Możesz je również znaleźć w bibliotekach takich jak Apollo: `onCompleted`, `onError`, itp.

### Użyj sąsiedniego komponentu do wyciągania logiki `useEffect` lub pobierania danych

Jeśli czujesz, że musisz dodać `useEffect` w swoim głównym komponencie, powinieneś rozważyć wyciągnięcie go do komponentu bocznego.

To samo możesz zastosować do logiki pobierania danych, z użyciem haków Apollo.

```tsx
// ❌ Bad, will cause re-renders even if data is not changing, 
//    because useEffect needs to be re-evaluated
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
// ✅ Good, will not cause re-renders if data is not changing, 
//   because useEffect is re-evaluated in another sibling component
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>
);
```

### Używaj stanów rodzinnych Recoil i selektorów rodzinnych Recoil

Stany rodzinne i selektory rodziny Recoil to świetny sposób na unikanie ponownych renderowań.

Są przydatne, gdy trzeba przechowywać listę przedmiotów.

### Nie powinieneś używać `React.memo(MyComponent)`

Unikaj używania `React.memo()`, ponieważ nie rozwiązuje to przyczyny ponownego renderowania, ale zamiast tego łamie łańcuch ponownego renderowania, co może prowadzić do nieoczekiwanego zachowania i uczynić kod trudnym do refaktoryzacji.

### Ogranicz użycie `useCallback` lub `useMemo`

Często nie są one konieczne i utrudnią czytelność i konserwację kodu dla zysków w wydajności które są nieznaczące.

## Console.logs

Instrukcje `console.log` są wartościowe podczas dewelopmentu, oferując wgląd w czasie rzeczywistym w wartości zmiennych i przepływ kodu. Ale pozostawienie ich w kodzie produkcyjnym może prowadzić do różnych problemów:

1. **Wydajność**: Nadmierne logowanie może wpływać na wydajność podczas działania, szczególnie w aplikacjach po stronie klienta.

2. **Bezpieczeństwo**: Logowanie danych wrażliwych może ujawnić ważne informacje każdemu, kto przegląda konsolę przeglądarki.

3. **Przejrzystość**: Wypełnienie konsoli logami może zamazać ważne ostrzeżenia lub błędy, które deweloperzy lub narzędzia muszą zobaczyć.

4. **Profesjonalizm**: Użytkownicy końcowi lub klienci sprawdzający konsolę i widzący mnóstwo logów mogą poddawać w wątpliwość jakość i wykończenie kodu.

Upewnij się, że usuniesz wszystkie `console.logs` przed przesłaniem kodu do produkcji.

## Nazewnictwo

### Nazewnictwo zmiennych

Nazwy zmiennych powinny dokładnie opisywać cel lub funkcję zmiennej.

#### Problem z ogólnymi nazwami

Ogólne nazwy w programowaniu nie są idealne, ponieważ brakuje im specyficzności, co prowadzi do niejasności i zmniejszonej czytelności kodu. Takie nazwy nie przekazują celu zmiennej lub funkcji, co utrudnia deweloperom zrozumienie intencji kodu bez głębszego dochodzenia. Może to prowadzić do zwiększonego czasu debugowania, większej podatności na błędy oraz trudności w utrzymaniu i współpracy. Tymczasem, opisowe nazewnictwo sprawia, że kod jest samowyjaśniający się i łatwiejszy do nawigacji, poprawiając jakość kodu i wydajność dewelopera.

```tsx
// ❌ Bad, uses a generic name that doesn't communicate its
//    purpose or content clearly
const [value, setValue] = useState('');
```

```tsx
// ✅ Good, uses a descriptive name
const [email, setEmail] = useState('');
```

#### Niektóre słowa do unikania w nazwach zmiennych

- attrapa

### Obsługa zdarzeń

Nazwy obsług procedur zdarzeń powinny zaczynać się od `handle`, podczas gdy `on` jest prefiksem używanym do nazwania zdarzeń w atrybutach komponentu.

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

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

## Opcjonalne Atrybuty

Unikaj przekazywania wartości domyślnej dla opcjonalnego atrybutu.

**PRZYKŁAD**

Zobacz komponent `EmailField` zdefiniowany poniżej:

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

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

**Zastosowanie**

```tsx
// ❌ Bad, passing in the same value as the default value adds no value
const Form = () => <EmailField value="username@email.com" disabled={false} />;
```

```tsx
// ✅ Good, assumes the default value
const Form = () => <EmailField value="username@email.com" />;
```

## Komponent jako atrybut

Spróbuj, o ile to możliwe, przekazywać niezainicjowane komponenty jako props, aby dzieci mogły same decydować, jakie propsy potrzebują przesłać.

Najczęstszym przykładem są komponenty ikon:

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

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

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

Aby React zrozumiał, że komponent to komponent, musisz użyć PascalCase, aby później zainicjować go jako `<MyIcon>`.

## Prop Drilling: Zachowaj Minimalizm

Prop drilling w kontekście React, odnosi się do praktyki przekazywania zmiennych stanu i ich ustawień przez wiele warstw komponentów, nawet jeśli komponenty pośrednie ich nie używają. Chociaż czasami jest to konieczne, nadmierne prop drilling może prowadzić do:

1. **Zmniejszona czytelność**: Śledzenie, skąd pochodzi prop lub gdzie jest używany, może stać się skomplikowane w głęboko zagnieżdżonej strukturze komponentów.

2. **Wyzwania związane z utrzymaniem**: Zmiany w strukturze prop jednego komponentu mogą wymagać dostosowań w kilku komponentach, nawet jeśli bezpośrednio nie używają tego prop.

3. **Zmniejszona możliwość ponownego użycia komponentu**: Komponent otrzymujący wiele propsów tylko po to, aby przesłać je dalej, staje się mniej uniwersalny i trudniejszy do ponownego użycia w różnych kontekstach.

Jeśli czujesz, że używasz nadmiernego prop drilling, zobacz [najlepsze praktyki zarządzania stanem](#state-management).

## Importuj

Podczas importowania, wybieraj przypisane aliasy zamiast szczegółowych lub względnych ścieżek.

**Aliasy uchwytu**

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

**Zastosowanie**

```tsx
// ❌ Bad, specifies the entire relative path
import {
  CatalogDecorator
} from '../../../../../testing/decorators/CatalogDecorator';
import {
  ComponentDecorator
} from '../../../../../testing/decorators/ComponentDecorator';
```

```tsx
// ✅ Good, utilises the designated aliases
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from 'twenty-ui/testing';
```

## Walidacja schematu

[Zod](https://github.com/colinhacks/zod) jest walidatorem schematów dla obiektów nieopisanych:

```js
const validationSchema = z
  .object({
    exist: z.boolean(),
    email: z
      .string()
      .email('Email must be a valid email'),
    password: z
      .string()
      .regex(PASSWORD_REGEX, 'Password must contain at least 8 characters'),
  })
  .required();

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

## Zmiany przełomowe

Zawsze wykonuj dokładne testy ręczne przed kontynuacją, aby zagwarantować, że modyfikacje nie spowodowały zakłóceń w innych miejscach, biorąc pod uwagę, że testy nie zostały jeszcze kompleksowo zintegrowane.

