Nederlands

Ontdek best practices voor het gebruik van TypeScript met React om robuuste, schaalbare en onderhoudbare webapplicaties te bouwen. Leer over projectstructuur, componentontwerp, testen en optimalisatie.

TypeScript met React: Best Practices voor Schaalbare en Onderhoudbare Applicaties

TypeScript en React zijn een krachtige combinatie voor het bouwen van moderne webapplicaties. TypeScript voegt statische typering toe aan JavaScript, wat de codekwaliteit en onderhoudbaarheid verbetert, terwijl React een declaratieve en op componenten gebaseerde aanpak biedt voor het bouwen van gebruikersinterfaces. Deze blogpost verkent best practices voor het gebruik van TypeScript met React om robuuste, schaalbare en onderhoudbare applicaties te creëren die geschikt zijn voor een wereldwijd publiek.

Waarom TypeScript met React gebruiken?

Voordat we ingaan op de best practices, laten we eerst begrijpen waarom TypeScript een waardevolle toevoeging is aan React-ontwikkeling:

Een TypeScript React-project opzetten

Create React App gebruiken

De eenvoudigste manier om een nieuw TypeScript React-project te starten is met Create React App en de TypeScript-template:

npx create-react-app my-typescript-react-app --template typescript

Dit commando zet een basis React-project op met TypeScript geconfigureerd, inclusief de benodigde afhankelijkheden en een tsconfig.json-bestand.

tsconfig.json configureren

Het tsconfig.json-bestand is het hart van je TypeScript-configuratie. Hier zijn enkele aanbevolen instellingen:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}

Belangrijke opties om te overwegen:

Best Practices voor React-componenten met TypeScript

Component Props typeren

Een van de belangrijkste aspecten van het gebruik van TypeScript met React is het correct typeren van je component props. Gebruik interfaces of type-aliassen om de vorm van het props-object te definiëren.

interface MyComponentProps {
  name: string;
  age?: number; // Optionele prop
  onClick: () => void;
}

const MyComponent: React.FC = ({ name, age, onClick }) => {
  return (
    

Hallo, {name}!

{age &&

Je bent {age} jaar oud.

}
); };

Het gebruik van React.FC<MyComponentProps> zorgt ervoor dat het component een functioneel component is en dat de props correct getypeerd zijn.

Component State typeren

Als je class-componenten gebruikt, moet je ook de state van het component typeren. Definieer een interface of type-alias voor het state-object en gebruik deze in de componentdefinitie.

interface MyComponentState {
  count: number;
}

class MyComponent extends React.Component<{}, MyComponentState> {
  state: MyComponentState = {
    count: 0
  };

  handleClick = () => {
    this.setState({
      count: this.state.count + 1
    });
  };

  render() {
    return (
      

Aantal: {this.state.count}

); } }

Voor functionele componenten die de useState-hook gebruiken, kan TypeScript vaak het type van de state-variabele afleiden, maar je kunt het ook expliciet opgeven:

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    

Aantal: {count}

); };

Type Guards gebruiken

Type guards zijn functies die het type van een variabele binnen een specifieke scope verfijnen. Ze zijn nuttig bij het omgaan met union-types of wanneer je moet verzekeren dat een variabele een specifiek type heeft voordat je een operatie uitvoert.

interface Circle {
  kind: "circle";
  radius: number;
}

interface Square {
  kind: "square";
  side: number;
}

type Shape = Circle | Square;

function isCircle(shape: Shape): shape is Circle {
  return shape.kind === "circle";
}

function getArea(shape: Shape): number {
  if (isCircle(shape)) {
    return Math.PI * shape.radius ** 2;
  } else {
    return shape.side ** 2;
  }
}

De isCircle-functie is een type guard die controleert of een Shape een Circle is. Binnen het if-blok weet TypeScript dat shape een Circle is en staat het je toe om de radius-eigenschap te benaderen.

Events afhandelen

Bij het afhandelen van events in React met TypeScript is het belangrijk om het event-object correct te typeren. Gebruik het juiste event-type uit de React-namespace.

const MyComponent: React.FC = () => {
  const handleChange = (event: React.ChangeEvent) => {
    console.log(event.target.value);
  };

  return (
    
  );
};

In dit voorbeeld wordt React.ChangeEvent<HTMLInputElement> gebruikt om het event-object voor een change-event op een input-element te typeren. Dit geeft toegang tot de target-eigenschap, wat een HTMLInputElement is.

Projectstructuur

Een goed gestructureerd project is cruciaal voor onderhoudbaarheid en schaalbaarheid. Hier is een voorgestelde projectstructuur voor een TypeScript React-applicatie:

src/
├── components/
│   ├── MyComponent/
│   │   ├── MyComponent.tsx
│   │   ├── MyComponent.module.css
│   │   └── index.ts
├── pages/
│   ├── HomePage.tsx
│   └── AboutPage.tsx
├── services/
│   ├── api.ts
│   └── auth.ts
├── types/
│   ├── index.ts
│   └── models.ts
├── utils/
│   ├── helpers.ts
│   └── constants.ts
├── App.tsx
├── index.tsx
├── react-app-env.d.ts
└── tsconfig.json

Kernpunten:

Hooks gebruiken met TypeScript

Met React Hooks kun je state en andere React-functies gebruiken in functionele componenten. TypeScript werkt naadloos samen met Hooks, wat zorgt voor typeveiligheid en een verbeterde ontwikkelaarservaring.

useState

Zoals eerder getoond, kun je de state-variabele expliciet typeren bij gebruik van useState:

import React, { useState } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  return (
    

Aantal: {count}

); };

useEffect

Wanneer je useEffect gebruikt, let dan op de dependency array. TypeScript kan je helpen fouten op te sporen als je vergeet een afhankelijkheid op te nemen die binnen het effect wordt gebruikt.

import React, { useState, useEffect } from 'react';

const MyComponent: React.FC = () => {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `Aantal: ${count}`;
  }, [count]); // Voeg 'count' toe aan de dependency array

  return (
    

Aantal: {count}

); };

Als je count weglaat uit de dependency array, zal het effect slechts één keer worden uitgevoerd wanneer het component wordt gemount, en zal de documenttitel niet worden bijgewerkt wanneer de count verandert. TypeScript zal je waarschuwen voor dit potentiële probleem.

useContext

Bij het gebruik van useContext moet je een type opgeven voor de contextwaarde.

import React, { createContext, useContext } from 'react';

interface ThemeContextType {
  theme: string;
  toggleTheme: () => void;
}

const ThemeContext = createContext(undefined);

const ThemeProvider: React.FC = ({ children }) => {
  // Implementeer hier de themalogica
  return (
     {} }}>
      {children}
    
  );
};

const MyComponent: React.FC = () => {
  const { theme, toggleTheme } = useContext(ThemeContext) as ThemeContextType;

  return (
    

Thema: {theme}

); }; export { ThemeProvider, MyComponent };

Door een type voor de contextwaarde op te geven, zorg je ervoor dat de useContext-hook een waarde met het juiste type retourneert.

TypeScript React-componenten testen

Testen is een essentieel onderdeel van het bouwen van robuuste applicaties. TypeScript verbetert het testen door typeveiligheid en een betere codedekking te bieden.

Unit Testing

Gebruik testframeworks zoals Jest en React Testing Library om je componenten te unit-testen.

// MyComponent.test.tsx
import React from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import MyComponent from './MyComponent';

describe('MyComponent', () => {
  it('rendert het component met de juiste naam', () => {
    render();
    expect(screen.getByText('Hallo, John!')).toBeInTheDocument();
  });

  it('roept de onClick-handler aan wanneer op de knop wordt geklikt', () => {
    const onClick = jest.fn();
    render();
    fireEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

De type-checking van TypeScript helpt bij het opsporen van fouten in je tests, zoals het doorgeven van onjuiste props of het gebruiken van de verkeerde event handlers.

Integratietesten

Integratietests verifiëren dat verschillende delen van je applicatie correct samenwerken. Gebruik tools zoals Cypress of Playwright voor end-to-end testen.

Prestatieoptimalisatie

TypeScript kan ook helpen bij prestatieoptimalisatie door potentiële prestatieknelpunten vroeg in het ontwikkelingsproces op te sporen.

Memoization

Gebruik React.memo om functionele componenten te memoïzeren en onnodige re-renders te voorkomen.

import React from 'react';

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC = ({ name }) => {
  console.log('Rendering MyComponent');
  return (
    

Hallo, {name}!

); }; export default React.memo(MyComponent);

React.memo zal het component alleen opnieuw renderen als de props zijn gewijzigd. Dit kan de prestaties aanzienlijk verbeteren, vooral bij complexe componenten.

Code Splitting

Gebruik dynamische imports om je code op te splitsen in kleinere chunks en deze op aanvraag te laden. Dit kan de initiële laadtijd van je applicatie verminderen.

import React, { Suspense } from 'react';

const MyComponent = React.lazy(() => import('./MyComponent'));

const App: React.FC = () => {
  return (
    Laden...
}> ); };

React.lazy stelt je in staat om componenten dynamisch te importeren, die alleen worden geladen wanneer ze nodig zijn. Het Suspense-component biedt een fallback-UI terwijl het component laadt.

Conclusie

Het gebruik van TypeScript met React kan de kwaliteit, onderhoudbaarheid en schaalbaarheid van je webapplicaties aanzienlijk verbeteren. Door deze best practices te volgen, kun je de kracht van TypeScript benutten om robuuste en performante applicaties te bouwen die voldoen aan de behoeften van een wereldwijd publiek. Vergeet niet te focussen op duidelijke type-definities, een goed gestructureerde projectorganisatie en grondig testen om het succes van je projecten op lange termijn te verzekeren.

Verdere bronnen