---
title: Parhaat käytännöt
image: /images/user-guide/tips/light-bulb.png
---

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

Tämä asiakirja esittelee parhaat käytännöt, joita tulisi noudattaa työskenneltäessä frontend-käyttöliittymän parissa.

## Tilanhallinta

React ja Recoil hallitsevat tilanhallintaa koodipohjassa.

### Use `useRecoilState` to store state

It's good practice to create as many atoms as you need to store your state.

<Warning>

It's better to use extra atoms than trying to be too concise with props 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>
  );
}
```

### Älä käytä `useRef` tilan tallentamiseen

Vältä `useRef`:n käyttöä tilan tallentamiseen.

Jos haluat tallentaa tilan, sinun tulisi käyttää `useState` tai `useRecoilState`.

See [how to manage re-renders](#managing-re-renders) if you feel like you need `useRef` to prevent some re-renders from happening.

## Managing re-renders

Re-renders can be hard to manage in React.

Here are some rules to follow to avoid unnecessary re-renders.

Keep in mind that you can **always** avoid re-renders by understanding their cause.

### Work at the root level

Avoiding re-renders in new features is now made easy by eliminating them at the root level.

`PageChangeEffect`-sivutukikomponentti sisältää vain yhden `useEffect`:n, joka pitää sisällään kaiken logiikan sivun vaihdon toteuttamiseen.

Näin tiedät, että vain yksi paikka voi käynnistää uudelleenrendauksen.

### Mieti aina kahdesti ennen `useEffect`:n lisäämistä koodipohjaasi

Uudelleenrendaukset johtuvat usein tarpeettomasta `useEffect`:n käytöstä.

Sinun tulisi miettiä, tarvitsetko `useEffect`:n, vai voitko siirtää logiikan tapahtumankäsittelijäfunktioon.

You'll find it generally easy to move the logic in a `handleClick` or `handleChange` function.

Voit myös löytää niitä kirjastoista kuten Apollo: `onCompleted`, `onError`, jne.

### Use a sibling component to extract `useEffect` or data fetching logic

If you feel like you need to add a `useEffect` in your root component, you should consider extracting it in a sidecar component.

You can apply the same for data fetching logic, with Apollo hooks.

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

### Käytä Recoil perhetiloja ja Recoil perhevalitsimia

Recoil family states and selectors are a great way to avoid re-renders.

Ne ovat hyödyllisiä, kun sinun tarvitsee tallentaa lista kohteista.

### You shouldn't use `React.memo(MyComponent)`

Avoid using `React.memo()` because it does not solve the cause of the re-render, but instead breaks the re-render chain, which can lead to unexpected behavior and make the code very hard to refactor.

### Rajoita `useCallback` tai `useMemo` käyttöä

They are often not necessary and will make the code harder to read and maintain for a gain of performance that is unnoticeable.

## Console.logs

`console.log` statements are valuable during development, offering real-time insights into variable values and code flow. Mutta, niiden jättäminen tuotantokoodiin voi aiheuttaa useita ongelmia:

1. **Suorituskyky**: Liiallinen loggaaminen voi vaikuttaa suoritusaikasuorituskykyyn, erityisesti asiakaspään sovelluksissa.

2. **Turvallisuus**: Herkän tiedon loggaaminen voi paljastaa kriittistä tietoa kenelle tahansa, joka tarkistaa selaimen konsolin.

3. **Cleanliness**: Filling up the console with logs can obscure important warnings or errors that developers or tools need to see.

4. **Ammattimaisuus**: Lopulliset käyttäjät tai asiakkaat, jotka tarkistavat konsolin ja näkevät joukon lokimerkintöjä, saattavat kyseenalaistaa koodin laadun ja viimeistelyn.

Varmista, että poistat kaikki `console.log`:t ennen koodin työntämistä tuotantoon.

## Nimeäminen

### Muuttujien nimeäminen

Variable names ought to precisely depict the purpose or function of the variable.

#### Ongelma yleisten nimien kanssa

Yleiset nimet ohjelmoinnissa eivät ole ihanteellisia, koska niiltä puuttuu spesifisyys, mikä johtaa epäselvyyteen ja vähentää koodin luettavuutta. Tällaiset nimet eivät kykene välittämään muuttujan tai funktion tarkoitusta, mikä tekee haastavammaksi kehittäjille ymmärtää koodin tarkoitusta ilman syvempää tutkimusta. Tämä voi lisätä virheiden etsintään kuluvaa aikaa, lisätä alttiutta virheille ja vaikeuttaa ylläpitoa ja yhteistyötä. Samaan aikaan kuvaileva nimeäminen tekee koodista itsestäänselvän ja helpomman navigoida, parantaa koodin laatua ja kehittäjien tuottavuutta.

```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('');
```

#### Joidenkin sanojen välttäminen muuttujan nimissä

- dummy

### Tapahtumakäsittelijät

Tapahtumakäsittelijöiden nimet tulisi alkaa `handle`:lla, kun taas `on` on etuliite, jota käytetään nimeämään tapahtumat komponenttien props:issa.

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

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

## Valinnaiset propsit

Vältä oletusarvon välittämistä valinnaiselle propille.

**ESIMERKKI**

Otetaan alla määritelty `EmailField` komponentti:

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

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

**Käyttö**

```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" />;
```

## Komponentit propsina

Yritä mahdollisuuksien mukaan välittää alustamattomia komponentteja proppina, jotta alikomponentit voivat päättää itse, mitä proppia ne tarvitsevat välittää.

Yleisin esimerkki tästä on ikonit komponentteina:

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

Jotta React ymmärtää, että komponentti on komponentti, sinun tulee käyttää PascalCasea, jotta voit myöhemmin alustaa sen `<MyIcon>` muodossa.

## Prop Drilling: Pidä Se Minimissä

Prop drilling, React-kontekstissa, viittaa käytäntöön välittää tilamuuttujia ja niiden asettajia monien komponenttikerrosten läpi, vaikka välissä olevat komponentit eivät niitä käyttäisikään. Vaikka se on joskus tarpeen, liiallinen prop drilling voi johtaa:

1. **Vähentyneeseen Luettavuuteen**: Propin alkuperän tai sen käytön jäljittäminen voi muuttua monimutkaiseksi syvästi sisäkkäisissä komponenttistruktuureissa.

2. **Ylläpidon Haasteisiin**: Muutokset yhden komponentin proppirakenteessa saattavat vaatia säätöjä useassa komponentissa, vaikka ne eivät niitä suoraan käyttäisikään.

3. **Vähentyneeseen Komponentin Uudelleenkäytettävyyteen**: Komponentti, joka vastaanottaa paljon proppeja pelkästään niiden eteenpäin välittämistä varten, muuttuu vähemmän yleiskäyttöiseksi ja vaikeammin uudelleenkäytettäväksi eri konteksteissa.

Jos koet käyttäväsi liiallisesti prop drillingiä, katso [tilanhallinnan parhaat käytännöt](#state-management).

## Tuonti

Kun tuot, valitse nimikoidut aliasit mieluummin kuin määrittelemällä kokonaisia tai suhteellisia polkuja.

**Aliaset**

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

**Käyttö**

```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';
```

## Skeeman Vahvistus

[Zod](https://github.com/colinhacks/zod) on skeeman validoija tyypittämättömille olioille:

```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>;
```

## Merkittävät Muutokset

Tee aina perusteellinen käsitarkastus ennen kuin etenet, jotta voit taata, että muutokset eivät ole aiheuttaneet häiriöitä muualla, koska testejä ei ole vielä laajasti integroitu.

