--- title: Beste praksis image: /images/user-guide/tips/light-bulb.png --- Header Dette dokumentet skisserer de beste praksisene du bør følge når du jobber på frontend. ## Tilstandshåndtering React og Recoil håndterer tilstandshåndtering i kodebasen. ### Bruk `useRecoilState` for å lagre tilstand Det er en god praksis å lage så mange atomer som du trenger for å lagre tilstanden din. Det er bedre å bruke ekstra atomer enn å prøve å være for konsis med å bore props. ```tsx export const myAtomState = atom({ key: 'myAtomState', default: 'default value', }); export const MyComponent = () => { const [myAtom, setMyAtom] = useRecoilState(myAtomState); return (
setMyAtom(e.target.value)} />
); } ``` ### Ikke bruk `useRef` for å lagre tilstand Unngå å bruke `useRef` for å lagre tilstand. Hvis du vil lagre tilstand, bør du bruke `useState` eller `useRecoilState`. Se [hvordan håndtere omrendringer](#managing-re-renders) hvis du føler at du trenger `useRef` for å forhindre at noen omrendringer skjer. ## Håndtere omrendringer Omrendringer kan være vanskelige å håndtere i React. Her er noen regler å følge for å unngå unødvendige omrendringer. Husk at du **alltid** kan unngå omrendringer ved å forstå deres årsak. ### Arbeid på rotnivå Unngåelse av omrendringer i nye funksjoner er nå gjort enkelt ved å eliminere dem på rotnivå. The `PageChangeEffect` sidecar component contains just one `useEffect` that holds all the logic to execute on a page change. På denne måten vet du at det er bare ett sted som kan utløse en omrendering. ### Tenk deg nøye om før du legger til `useEffect` i din kodebase Omrendringer er ofte forårsaket av unødvendig `useEffect`. Du bør vurdere om du trenger `useEffect`, eller om du kan flytte logikken til en hendelseshåndtererfunksjon. Du vil generelt finne det enkelt å flytte logikken til en `handleClick` eller `handleChange`-funksjon. Du kan også finne dem i biblioteker som Apollo: `onCompleted`, `onError`, osv. ### Bruk en søskenkomponent for å trekke ut `useEffect` eller datahentingslogikk Hvis du føler at du trenger å legge til en `useEffect` i din rotkomponent, bør du vurdere å trekke den ut i en sidevognkomponent. Du kan bruke det samme for datahentingslogikk, med 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
{data}
; }; export const App = () => ( ); ``` ```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
{data}
; }; export const PageData = () => { const [data, setData] = useRecoilState(dataState); const [someDependency] = useRecoilState(someDependencyState); useEffect(() => { if(someDependency !== data) { setData(someDependency); } }, [someDependency]); return <>; }; export const App = () => ( ); ``` ### Bruk recoil familietilstander og recoil familieselektorer Recoil familietilstander og selektorer er en flott måte å unngå omrendringer på. De er nyttige når du trenger å lagre en liste over elementer. ### Du bør ikke bruke `React.memo(MyComponent)` Unngå bruk av `React.memo()` fordi det ikke løser årsaken til omrenderingen, men i stedet bryter omrenderingskjeden, noe som kan føre til uventet oppførsel og gjøre koden veldig vanskelig å refaktorere. ### Begrens bruken av `useCallback` eller `useMemo` De er ofte ikke nødvendige og vil gjøre koden vanskeligere å lese og vedlikeholde for en gevinst i ytelse som er umerkelig. ## Console.logs `console.log` setninger er verdifulle under utvikling, og tilbyr sanntidsinnsikt i variabelverdier og kodeflyt. Men å la dem være i produksjonskode kan føre til flere problemer: 1. **Ytelse**: Overdreven logging kan påvirke kjøringsytelsen, spesielt på klientapplikasjoner. 2. **Sikkerhet**: Logging av sensitiv data kan avsløre kritisk informasjon til alle som inspiserer nettleserens konsoll. 3. **Ryddighet**: Å fylle opp konsollen med logger kan skjule viktige advarsler eller feil som utviklere eller verktøy trenger å se. 4. **Profesjonalitet**: Sluttbrukere eller kunder som sjekker konsollen og ser en mengde loggutsagn kan stille spørsmål ved kvaliteten og finishen av koden. Forsikre deg om at du fjerner alle `console.logs` før du skyver koden til produksjon. ## Navngiving ### Variabelnavngiving Variabelnavn bør presist beskrive variablens hensikt eller funksjon. #### Problemet med generiske navn Generiske navn i programmering er ikke ideelle fordi de mangler spesifisitet, noe som fører til tvetydighet og redusert kodelesbarhet. Slike navn klarer ikke å formidle variabelen eller funksjonens hensikt, noe som gjør det utfordrende for utviklere å forstå kodenes intensjon uten dypere undersøkelser. Dette kan føre til økt feilsøkingstid, høyere sårbarhet for feil, og vansker ved vedlikehold og samarbeid. I mellomtiden gjør beskrivende navngiving koden selvforklarende og lettere å navigere, og øker kodekvaliteten og utviklerens produktivitet. ```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(''); ``` #### Noen ord å unngå i variabelnavn - dummy ### Hendelseshåndterere Hendelseshåndterernes navn bør starte med `handle`, mens `on` er et prefiks brukt for å navngi hendelser i komponentprops. ```tsx // ❌ Bad const onEmailChange = (val: string) => { // ... }; ``` ```tsx // ✅ Good const handleEmailChange = (val: string) => { // ... }; ``` ## Valgfrie Props Unngå å sende den standardverdien for en valgfri prop. **EKSEMPEL** Ta `EmailField` komponenten definert nedenfor: ```tsx type EmailFieldProps = { value: string; disabled?: boolean; }; const EmailField = ({ value, disabled = false }: EmailFieldProps) => ( ); ``` **Bruk** ```tsx // ❌ Bad, passing in the same value as the default value adds no value const Form = () => ; ``` ```tsx // ✅ Good, assumes the default value const Form = () => ; ``` ## Komponent som props Prøv så mye som mulig å sende ikke-instanserte komponenter som props, slik at barn kan bestemme selv hvilke props de trenger å sende. Det vanligste eksemplet på dette er ikonekomponenter. ```tsx const SomeParentComponent = () => ; // In MyComponent const MyComponent = ({ MyIcon }: { MyIcon: IconComponent }) => { const theme = useTheme(); return (
) }; ``` For at React skal forstå at komponenten er en komponent, må du bruke store bokstaver, for senere å instansiere den med `` ## Prop-gjennomgang: Hold det minimalt I React-sammenheng refererer prop-gjennomgang til praksisen med å sende tilstandsvariabler og deres settere gjennom mange komponentlag, selv om mellomliggende komponenter ikke bruker dem. Selv om det noen ganger er nødvendig, kan overdreven prop-gjennomgang føre til: 1. **Redusert Lesbarhet**: Å spore hvor en prop stammer fra eller hvor den brukes kan bli komplisert i en dypt nestet komponentstruktur. 2. **Vedlikeholdsutfordringer**: Endringer i en komponents prop-struktur kan kreve justeringer i flere komponenter, selv om de ikke direkte bruker propen. 3. **Redusert Komponentgjenbruk**: En komponent som mottar mange props kun for å sende dem videre blir mindre allsidig og vanskeligere å gjenbruke i forskjellige sammenhenger. Hvis du føler at du bruker overdreven prop-gjennomgang, se [beste praksis for tilstandshåndtering](#state-management). ## Importer Ved import, velg de angitte aliasene fremfor å spesifisere komplette eller relative stier. **Håndtak Aliaser** ```js { alias: { "~": path.resolve(__dirname, "src"), "@": path.resolve(__dirname, "src/modules"), "@testing": path.resolve(__dirname, "src/testing"), }, } ``` **Bruk** ```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'; ``` ## Schema-validering [Zod](https://github.com/colinhacks/zod) er skjema-valideren for utypede objekter. ```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; ``` ## Kritiske Endringer Utfør alltid grundig manuell testing før du går videre for å sikre at modifikasjoner ikke har forårsaket forstyrrelser andre steder, gitt at tester ennå ikke er omfattende integrert.