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
10 KiB
Plaintext
334 lines
10 KiB
Plaintext
---
|
|
title: Beste Praktyke
|
|
image: /images/user-guide/tips/light-bulb.png
|
|
---
|
|
|
|
<Frame>
|
|
<img src="/images/user-guide/tips/light-bulb.png" alt="Header" />
|
|
</Frame>
|
|
|
|
Hierdie dokument stel die beste praktyke uiteen wat u moet volg wanneer u aan die frontend werk.
|
|
|
|
## Toestandbestuur
|
|
|
|
React en Recoil hanteer toestand bestuur in die kodebasis.
|
|
|
|
### Gebruik `useRecoilState` om toestand op te slaan
|
|
|
|
Dit is goeie praktyk om soveel atome as wat nodig is te skep om jou toestand op te slaan.
|
|
|
|
<Warning>
|
|
|
|
Dit is beter om ekstra atome te gebruik as om te beknop met props-boor.
|
|
|
|
</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>
|
|
);
|
|
}
|
|
```
|
|
|
|
### Moenie `useRef` gebruik om toestand op te slaan nie
|
|
|
|
Vermy die gebruik van `useRef` om toestand op te slaan.
|
|
|
|
As jy toestand wil stoor, behoort jy `useState` of `useRecoilState` te gebruik.
|
|
|
|
Kyk na [hoe om hervervaardigings te bestuur](#managing-re-renders) as jy voel jy moet `useRef` gebruik om sekere hervervaardigings te voorkom.
|
|
|
|
## Bestuur van hervervaardigings
|
|
|
|
Hervervaardigings kan moeilik wees om in React te bestuur.
|
|
|
|
Hier is 'n paar reëls om te volg om onnodige hervervaardigings te vermy.
|
|
|
|
Hou in gedagte dat jy **altyd** hervervaardigings kan vermy deur hul oorsaak te verstaan.
|
|
|
|
### Werk op die wortelvlak
|
|
|
|
Dit is nou maklik om hervervaardigings uit nuwe funksies te vermy deur dit op die wortelvlak te elimineer.
|
|
|
|
Die `PageChangeEffect` kantmotor komponent bevat net een `useEffect` wat al die logika hou om op 'n bladsyverandering uit te voer.
|
|
|
|
Op daardie manier weet jy dat daar net een plek is wat 'n hervervaardiging kan veroorsaak.
|
|
|
|
### Dink altyd twee keer voor jy `useEffect` in jou kodebasis voeg.
|
|
|
|
Hervervaardigings word dikwels veroorsaak deur onnodige `useEffect`.
|
|
|
|
Jy moet dink of jy regtig `useEffect` benodig, of as jy die logika na 'n gebeurtenishanteerder funksie kan skuif.
|
|
|
|
Dit is oor die algemeen maklik om die logika in 'n `handleClick` of `handleChange` funksie te skuif.
|
|
|
|
Jy kan hulle ook vind in biblioteke soos Apollo: `onCompleted`, `onError`, ens.
|
|
|
|
### Use a sibling component to extract `useEffect` or data fetching logic
|
|
|
|
As jy voel jy moet 'n `useEffect` in jou wortelkomponent voeg, behoort jy dit in 'n kantmotor komponent te onttrek.
|
|
|
|
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>
|
|
);
|
|
```
|
|
|
|
### Gebruik recoil familie toestande en recoil familie selektore
|
|
|
|
Recoil familie toestande en selektore is 'n uitstekende manier om hervervaardigings te vermy.
|
|
|
|
Hulle is nuttig wanneer jy 'n lys van items moet stoor.
|
|
|
|
### Jy moet nie `React.memo(MyComponent)` gebruik nie.
|
|
|
|
Vermy die gebruik van `React.memo()` want dit los nie die oorsaak van die hervervaardiging op nie, maar breek eerder die hervervaardigingsketting, wat kan lei tot onverwagte gedrag en maak die kode baie moeilik om oor te doen.
|
|
|
|
### Beperk die gebruik van `useCallback` of `useMemo`
|
|
|
|
Hulle is dikwels nie nodig nie en sal die kode moeiliker maak om te lees en te onderhou vir 'n prestasie wins wat nie opvallend is nie.
|
|
|
|
## Konsolletjies
|
|
|
|
`console.log` stellings is waardevol tydens ontwikkeling, aangesien hulle real-time insigte bied in veranderlike waardes en kodevloei. Maar, om hulle in produksiekode te laat kan tot verskeie probleme lei:
|
|
|
|
1. **Prestasie**: Oormaat logboekhouding kan die runtime prestasie beïnvloed, veral op kliëntkant toepassings.
|
|
|
|
2. **Sekuriteit**: Logboekhouding van sensitiewe data kan kritiese inligting blootstel aan enigiemand wat die blaaier se konsole inspekteer.
|
|
|
|
3. **Netheid**: Deur die konsole vol te maak met logboeke kan belangrike waarskuwings of foute wat ontwikkelaars of gereedskap moet sien, verduister.
|
|
|
|
4. **Professionaliteit**: Eindgebruikers of kliënte wat die konsole kyk en 'n magdom logverklarings sien, kan die kwaliteit en afwerking van die kode bevraagteken.
|
|
|
|
Maak seker jy verwyder alle `console.logs` voordat jy die kode na produksie druk.
|
|
|
|
## Naamgewing
|
|
|
|
### Veranderlike Naamgewing
|
|
|
|
Veranderlike name behoort die doel of funksie van die verandering presies uit te druk.
|
|
|
|
#### Die probleem met generiese name
|
|
|
|
Generiese name in programmering is nie ideaal nie omdat hulle spesifisiteit kort, wat lei tot dubbelsinnigheid en verminderde kodeleesbaarheid. Sulke name slaag nie daarin om die doel van die veranderlike of funksie oor te dra nie, wat dit moeilik maak vir ontwikkelaars om die kode se bedoeling te verstaan sonder 'n dieper ondersoek. Dit kan lei tot verhoging in foutspeuring-tyd, hoër vatbaarheid vir foute, en moeilikhede in onderhoud en samewerking. Intussen maak beskrywende naamgewing die kode selfverduidelikend en makliker om te navigeer, wat die kode kwaliteit en ontwikkelaar-produktiwiteit verbeter.
|
|
|
|
```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('');
|
|
```
|
|
|
|
#### Sommige woorde om in veranderlike name te vermy
|
|
|
|
- dummy
|
|
|
|
### Gebeurtenishanteerders
|
|
|
|
Gebeurtenishanteerdername behoort te begin met `handle`, terwyl `on` 'n voorvoegsel is wat gebruik word om gebeurtenisse in komponentrekwekkinge te benoem.
|
|
|
|
```tsx
|
|
// ❌ Bad
|
|
const onEmailChange = (val: string) => {
|
|
// ...
|
|
};
|
|
```
|
|
|
|
```tsx
|
|
// ✅ Good
|
|
const handleEmailChange = (val: string) => {
|
|
// ...
|
|
};
|
|
```
|
|
|
|
## Opsionele Eienskappe
|
|
|
|
Vermy om die verstekwaarde vir 'n opsionele eienskap oor te dra.
|
|
|
|
**VOORBEELD**
|
|
|
|
Neem die `EmailField` komponent hieronder gedefinieer:
|
|
|
|
```tsx
|
|
type EmailFieldProps = {
|
|
value: string;
|
|
disabled?: boolean;
|
|
};
|
|
|
|
const EmailField = ({ value, disabled = false }: EmailFieldProps) => (
|
|
<TextInput value={value} disabled={disabled} fullWidth />
|
|
);
|
|
```
|
|
|
|
**Gebruik**
|
|
|
|
```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" />;
|
|
```
|
|
|
|
## Component as props
|
|
|
|
Probeer soveel as moontlik om nie-geïnstansieerde komponente as eienskappe deur te gee, sodat kinders self kan besluit watter eienskappe hulle moet deurgee.
|
|
|
|
Die mees algemene voorbeeld daarvoor is ikoon-komponente:
|
|
|
|
```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>
|
|
)
|
|
};
|
|
```
|
|
|
|
Vir React om te verstaan dat die komponent 'n komponent is, moet jy PascalCase gebruik, om dit later met `<MyIcon>` te instantieer.
|
|
|
|
## Eienskapsboor: Hou Dit Minimaal
|
|
|
|
Eienskapsboor, in die React-konteks, verwys na die gebruik om toestandsveranderlikes en hul stelers deur baie komponentlae te stuur, selfs al gebruik tussentydse komponente hulle nie. Alhoewel soms nodig, kan oormatige eienskapsboor lei tot:
|
|
|
|
1. **Verminderde Leesbaarheid**: Om te kyk waar 'n eienskap vandaan kom of waar dit gebruik word, kan verwarrend raak in 'n diep geneste komponentstruktuur.
|
|
|
|
2. **Onderhoudsuitdagings**: Veranderinge in een komponent se eienskapstruktuur kan aanpassings vereis in verskeie komponente, selfs al gebruik hulle nie direk die eienskap nie.
|
|
|
|
3. **Verminderde Hergebruik van Komponente**: 'n Komponent wat baie eienskappe ontvang net om dit af te gee, word minder algemeen en moeiliker om in verskillende kontekste te hergebruik.
|
|
|
|
As jy voel dat jy oormatige eienskapsboor gebruik, sien [toestandbestuursbeste-praktyke](#state-management).
|
|
|
|
## Invoer
|
|
|
|
By invoer, kies eerder vir die aangewysde byname as om volledige of relatiewe paaie te spesifiseer.
|
|
|
|
**Die Byname**
|
|
|
|
```js
|
|
{
|
|
alias: {
|
|
"~": path.resolve(__dirname, "src"),
|
|
"@": path.resolve(__dirname, "src/modules"),
|
|
"@testing": path.resolve(__dirname, "src/testing"),
|
|
},
|
|
}
|
|
```
|
|
|
|
**Gebruik**
|
|
|
|
```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';
|
|
```
|
|
|
|
## Skemavalidering
|
|
|
|
[Zod](https://github.com/colinhacks/zod) is die skemavalideerder vir ongetikte objekte:
|
|
|
|
```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>;
|
|
```
|
|
|
|
## Kritieke Veranderings
|
|
|
|
Voer altyd deeglike handmatige toetsing uit voordat u voortgaan, om te verseker dat wysigings nie ontwrigting elders veroorsaak het nie, aangesien toetse nog nie omvattend geïntegreer is nie.
|
|
|