--- title: Guida di stile icon: pennello description: Convenzioni di codice e buone pratiche per contribuire a Twenty. --- ## React ### Solo componenti funzionali Usa sempre componenti funzionali TSX con export nominati. ```tsx // ❌ Bad const MyComponent = () => { return
Hello World
; }; export default MyComponent; // ✅ Good export function MyComponent() { return
Hello World
; }; ``` ### Props Crea un tipo denominato `{ComponentName}Props`. Usa la destrutturazione. Non usare `React.FC`. ```tsx type MyComponentProps = { name: string; }; export const MyComponent = ({ name }: MyComponentProps) =>
Hello {name}
; ``` ### Niente spread di una singola variabile nelle props ```tsx // ❌ Bad const MyComponent = (props: MyComponentProps) => ; // ✅ Good const MyComponent = ({ prop1, prop2 }: MyComponentProps) => ; ``` ## Gestione dello stato ### Atomi Jotai per lo stato globale ```tsx import { createAtomState } from '@/ui/utilities/state/jotai/utils/createAtomState'; import { useAtomState } from '@/ui/utilities/state/jotai/hooks/useAtomState'; export const myAtomState = createAtomState({ key: 'myAtomState', defaultValue: 'default value', }); ``` * Preferisci gli atomi al prop drilling * Non usare `useRef` per lo stato — usa `useState` o gli atomi * Usa famiglie di atomi e selettori per le liste ### Evita i re-render inutili * Estrai `useEffect` e il recupero dei dati in componenti sidecar fratelli * Preferisci i gestori di eventi (`handleClick`, `handleChange`) a `useEffect` * Non usare `React.memo()` — risolvi invece la causa principale * Limita l'uso di `useCallback` o `useMemo` ```tsx // ❌ Bad — useEffect in the same component causes re-renders export const Page = () => { const [data, setData] = useAtomState(dataState); const [dep] = useAtomState(depState); useEffect(() => { setData(dep); }, [dep]); return
{data}
; }; // ✅ Good — extract into sibling export const PageData = () => { const [data, setData] = useAtomState(dataState); const [dep] = useAtomState(depState); useEffect(() => { setData(dep); }, [dep]); return <>; }; export const Page = () => { const [data] = useAtomState(dataState); return
{data}
; }; ``` ## TypeScript * **`type` invece di `interface`** — più flessibile, più facile da comporre * **Letterali di stringa invece degli enum** — tranne per gli enum generati da GraphQL codegen e le API interne della libreria * **Niente `any`** — TypeScript rigoroso applicato * **Niente import di tipo** — usa import normali (applicato da Oxlint `typescript/consistent-type-imports`) * **Usa [Zod](https://github.com/colinhacks/zod)** per la validazione a runtime di oggetti non tipizzati ## JavaScript ```tsx // Use nullish-coalescing (??) instead of || const value = process.env.MY_VALUE ?? 'default'; // Use optional chaining onClick?.(); ``` ## Denominazione * **Variabili**: camelCase, descrittive (`email` non `value`, `fieldMetadata` non `fm`) * **Costanti**: SCREAMING_SNAKE_CASE * **Tipi/Classi**: PascalCase * **File/directory**: kebab-case (`.component.tsx`, `.service.ts`, `.entity.ts`) * **Gestori di eventi**: `handleClick` (non `onClick` per la funzione gestore) * **Props dei componenti**: metti come prefisso il nome del componente (`ButtonProps`) * **Componenti styled**: metti come prefisso `Styled` (`StyledTitle`) ## Stile Usa i componenti styled di [Linaria](https://github.com/callstack/linaria). Usa i valori del tema — evita `px`, `rem` o colori hardcoded. ```tsx // ❌ Bad const StyledButton = styled.button` color: #333333; font-size: 1rem; margin-left: 4px; `; // ✅ Good const StyledButton = styled.button` color: ${({ theme }) => theme.font.color.primary}; font-size: ${({ theme }) => theme.font.size.md}; margin-left: ${({ theme }) => theme.spacing(1)}; `; ``` ## Importazioni Usa gli alias invece dei percorsi relativi: ```tsx // ❌ Bad import { Foo } from '../../../../../testing/decorators/Foo'; // ✅ Good import { Foo } from '~/testing/decorators/Foo'; import { Bar } from '@/modules/bar/components/Bar'; ``` ## Struttura delle cartelle ``` front └── modules/ # Feature modules │ └── module1/ │ ├── components/ │ ├── constants/ │ ├── contexts/ │ ├── graphql/ (fragments, queries, mutations) │ ├── hooks/ │ ├── states/ (atoms, selectors) │ ├── types/ │ └── utils/ └── pages/ # Route-level components └── ui/ # Reusable UI components (display, input, feedback, ...) ``` * I moduli possono importare da altri moduli, ma `ui/` dovrebbe restare privo di dipendenze * Usa le sottocartelle `internal/` per il codice privato del modulo * Componenti sotto le 300 righe, servizi sotto le 500 righe