8cadd00d34
Created by Github action --------- Co-authored-by: Crowdin Bot <support+bot@crowdin.com> Co-authored-by: github-actions <github-actions@twenty.com>
334 lines
11 KiB
Plaintext
334 lines
11 KiB
Plaintext
---
|
|
title: Legjobb gyakorlatok
|
|
image: /images/user-guide/tips/light-bulb.png
|
|
---
|
|
|
|
<Frame>
|
|
<img src="/images/user-guide/tips/light-bulb.png" alt="Header" />
|
|
</Frame>
|
|
|
|
Ez a dokumentum ismerteti azokat a legjobb gyakorlatokat, amelyeket követned kell, amikor a frontend fejlesztésen dolgozol.
|
|
|
|
## Állapotkezelés
|
|
|
|
React és Recoil kezelik az állapotkezelést a kódbázisban.
|
|
|
|
### Használja a `useRecoilState`-et az állapot tárolására
|
|
|
|
Jó gyakorlat annyi atomot létrehozni, amennyire szükséged van az állapot tárolásához.
|
|
|
|
<Warning>
|
|
|
|
Érdemesebb extra atomokat használni, mint túlságosan szorosan tartani a tulajdonságfúrást.
|
|
|
|
</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>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Ne használja az `useRef`-et az állapot tárolására
|
|
|
|
Kerüld az `useRef` használatát állapot tárolására.
|
|
|
|
Ha állapotot szeretnél tárolni, használd a `useState`-t vagy a `useRecoilState`-et.
|
|
|
|
Nézd meg, hogyan kezeld a re-rajzolásokat [re-rajzolások kezelése](#managing-re-renders) ha úgy érzed, az `useRef`-re van szükséged, hogy elkerülj néhány újra-rajzolást.
|
|
|
|
## Re-rajzolások kezelése
|
|
|
|
A re-rajzolásokat nehéz lehet kezelni a React-ben.
|
|
|
|
Íme néhány szabály, amelyet követned kell, hogy elkerüld a felesleges újra-rajzolásokat.
|
|
|
|
Tartsd észben, hogy **mindig** elkerülheted a re-rajzolásokat az okok megértésével.
|
|
|
|
### Dolgozz gyökeri szinten
|
|
|
|
A re-rajzolások elkerülése az új funkciókban könnyebbé vált azáltal, hogy megszüntették azokat gyökeri szinten.
|
|
|
|
A `PageChangeEffect` segédkomponens csak egy `useEffect`-et tartalmaz, ami minden logikát tartalmaz, amit egy lapváltáskor végre kell hajtani.
|
|
|
|
Így tudod, hogy csak egy hely van, ami kiválthat egy újra-rajzolást.
|
|
|
|
### Mindig gondolkodj kétszer, mielőtt `useEffect`-et adsz a kódbázisodhoz
|
|
|
|
A re-rajzolásokat gyakran szükségtelen `useEffect` okozza.
|
|
|
|
Gondold meg, hogy szükséged van-e `useEffect`-re, vagy áthelyezheted a logikát egy eseménykezelő függvénybe.
|
|
|
|
Általában könnyen áthelyezheted a logikát egy `handleClick` vagy `handleChange` függvénybe.
|
|
|
|
Könyvtárakban, például az Apollóban is megtalálhatóak: `onCompleted`, `onError`, stb.
|
|
|
|
### Használj testvérkomponenst az `useEffect` vagy adatlekérő logika kiterjesztésére
|
|
|
|
Ha úgy érzed, `useEffect`-et kell hozzáadnod a gyökérkomponensedhez, fontold meg egy segédkomponensbe való áthelyezését.
|
|
|
|
Ugyanez vonatkozik az adatlekérő logikára is, például Apollo horgokkal.
|
|
|
|
```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>
|
|
);
|
|
```
|
|
|
|
### Használj Recoil család állapotokat és Recoil családi szelektorokat
|
|
|
|
A Recoil családi állapotok és szelektorok nagyszerű módjai az újra-rajzolások elkerülésének.
|
|
|
|
Hasznosak, ha egy lista elemeit kell tárolni.
|
|
|
|
### Nem szabad `React.memo(MyComponent)`-et használni
|
|
|
|
Kerüld a `React.memo()` használatát, mert ez nem oldja meg az újra-rajzolás okát, hanem megszakítja az újra-rajzolási láncot, ami váratlan viselkedéshez vezethet és nehezítheti a kód átalakítását.
|
|
|
|
### Korlátozd a `useCallback` vagy `useMemo` használatát
|
|
|
|
Gyakran szükségtelenek, és megnehezítik a kód olvasását és karbantartását a szinte észrevehetetlen teljesítménynövekedésért cserébe.
|
|
|
|
## Konzol.logok
|
|
|
|
A `console.log` utasítások értékesek a fejlesztés során, mivel valós idejű betekintést nyújtanak a változók értékébe és a kódfolyamatba. De ha a gyártási kódban hagyják őket, számos problémához vezethet:
|
|
|
|
1. **Teljesítmény**: A túlzott naplózás befolyásolhatja a futásidejű teljesítményt, különösen kliens oldali alkalmazásokban.
|
|
|
|
2. **Biztonság**: Érzékeny adatok naplózása kritikus információkat tárhat fel bárki számára, aki ellenőrzi a böngésző konzolját.
|
|
|
|
3. **Tisztaság**: A konzol naplókkal való feltöltése elfedheti a fontos figyelmeztetéseket vagy hibákat, amelyekre a fejlesztőknek vagy eszközöknek szüksége van.
|
|
|
|
4. **Szakmaiság**: Ha a végfelhasználók vagy ügyfelek ellenőrzik a konzolt, és számos naplónyilatkozatot látnak, megkérdőjelezhetik a kód minőségét és csiszoltságát.
|
|
|
|
Győződj meg arról, hogy minden `console.log`-ot eltávolítasz, mielőtt a kódot a gyártásba juttatnád.
|
|
|
|
## Elnevezés
|
|
|
|
### Változónév adása
|
|
|
|
A változóneveknek pontosan kell ábrázolniuk a változó célját vagy funkcióját.
|
|
|
|
#### A probléma az általános nevekkel
|
|
|
|
Az általános nevek a programozásban nem ideálisak, mivel hiányzik a specifikációjuk, ami bizonytalansághoz és a kód olvashatóságának csökkenéséhez vezet. Az ilyen nevek nem tudják közvetíteni a változó vagy függvény célját, ami megnehezíti a fejlesztők számára a kód szándékának megértését anélkül, hogy mélyebben kutatnának. Ez megnövekedett hibakeresési időt, nagyobb hajlandóságot a hibákra és nehézségeket okoz a karbantartásban és az együttműködésben. Eközben a leíró elnevezés megkönnyíti a kód önmgot és egyszerűbbé teszi a navigálást, javítva a kódminőséget és a fejlesztői termelékenységet.
|
|
|
|
```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('');
|
|
```
|
|
|
|
#### Néhány szó, amit el kell kerülni a változónevekben
|
|
|
|
- próba
|
|
|
|
### Eseménykezelők
|
|
|
|
Az eseménykezelők neve `handle`-lel kell kezdődjön, míg az `on` előtagot az események nevének kell használni az összetevők tulajdonságaiban.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
const onEmailChange = (val: string) => {
|
|
// ...
|
|
};
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const handleEmailChange = (val: string) => {
|
|
// ...
|
|
};
|
|
```
|
|
|
|
## Opcionális tulajdonságok
|
|
|
|
Kerüld el az alapértelmezett érték átadását egy opcionális tulajdonsághoz.
|
|
|
|
**PÉLDA**
|
|
|
|
Tekintsd meg a lent meghatározott `EmailField` komponenst:
|
|
|
|
```tsx
|
|
type EmailFieldProps = {
|
|
value: string;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
|
|
<TextInput value={value} disabled={disabled} fullWidth />
|
|
);
|
|
```
|
|
|
|
**Használat**
|
|
|
|
```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" />;
|
|
```
|
|
|
|
## Összetevő tulajdonságként
|
|
|
|
Próbálj meg lehetőleg kezeletlen komponenseket propsként átadni, így a gyermekek eldönthetik, hogy milyen propsokat kell továbbítaniuk.
|
|
|
|
A leggyakoribb példa erre az ikon komponensek:
|
|
|
|
```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>
|
|
)
|
|
};
|
|
```
|
|
|
|
Ahhoz, hogy a React felismerje, hogy a komponens egy komponens, PascalCase-t kell használni, hogy később `<MyIcon>`-tal lehessen példányosítani.
|
|
|
|
## Prop fúrás: Tartsd minimális szinten
|
|
|
|
A prop fúrás a React kontextusban arra utal, hogy hogyan adod át az állapotváltozókat és azok beállítóit több komponensrétegen keresztül, még ha a köztes elemek nem is használják őket. Habár néha szükséges, a túlzott prop fúrás ahhoz vezethet, hogy:
|
|
|
|
1. **Olvashatóság csökkenése**: Egy prop eredetét vagy felhasználási helyét követni bonyolulttá válhat egy mélyen beágyazott komponens szerkezetben.
|
|
|
|
2. **Fenntartási kihívások**: Egy komponens prop szerkezetének megváltoztatása több komponens módosítását is igényelheti, még akkor is, ha közvetlenül nem használják a propot.
|
|
|
|
3. **Komponens újrahasznosíthatóság csökkenése**: Egy komponens, amely sok propot csak átadás céljából kap, kevésbé lesz általános célú és nehezebben újrahasznosítható különböző kontextusokban.
|
|
|
|
Ha úgy érzed, hogy túlzottan használod a prop fúrást, nézd meg az [állapotkezelési legjobb gyakorlatokat](#state-management).
|
|
|
|
## Importálás
|
|
|
|
Az importálás során válaszd a kijelölt álnév használatát a teljes vagy relatív útvonal helyett.
|
|
|
|
**Kezelőnevek**
|
|
|
|
```js
|
|
{
|
|
alias: {
|
|
"~": path.resolve(__dirname, "src"),
|
|
"@": path.resolve(__dirname, "src/modules"),
|
|
"@testing": path.resolve(__dirname, "src/testing"),
|
|
},
|
|
}
|
|
```
|
|
|
|
**Használat**
|
|
|
|
```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';
|
|
```
|
|
|
|
## Séma érvényesítés
|
|
|
|
[Zod](https://github.com/colinhacks/zod) az érzelem nélküli objektumok sémavezérlője.
|
|
|
|
```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>;
|
|
```
|
|
|
|
## Törő változások
|
|
|
|
Mindig végezz alapos manuális tesztelést a folytatás előtt, hogy garantáld, hogy a módosítások nem okoznak hibákat máshol, tekintettel arra, hogy a tesztek még nem kerültek széleskörűen integrálásra.
|
|
|