Svenska

Bästa praxis för TypeScript med React: Bygg robusta, skalbara och underhållsbara webbapplikationer. Fokus på struktur, komponenter, testning och optimering.

TypeScript med React: Bästa praxis för skalbara och underhållsbara applikationer

TypeScript och React är en kraftfull kombination för att bygga moderna webbapplikationer. TypeScript tillför statisk typning till JavaScript, vilket förbättrar kodkvalitet och underhållbarhet, medan React erbjuder ett deklarativt och komponentbaserat tillvägagångssätt för att bygga användargränssnitt. Detta blogginlägg utforskar bästa praxis för att använda TypeScript med React för att skapa robusta, skalbara och underhållsbara applikationer lämpliga för en global publik.

Varför använda TypeScript med React?

Innan vi dyker ner i bästa praxis, låt oss förstå varför TypeScript är ett värdefullt tillskott till React-utveckling:

Konfigurera ett TypeScript React-projekt

Använda Create React App

Det enklaste sättet att starta ett nytt TypeScript React-projekt är att använda Create React App med TypeScript-mallen:

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

Detta kommando sätter upp ett grundläggande React-projekt med TypeScript konfigurerat, inklusive nödvändiga beroenden och en tsconfig.json-fil.

Konfigurera tsconfig.json

Filen tsconfig.json är hjärtat i din TypeScript-konfiguration. Här är några rekommenderade inställningar:

{
  "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"
  ]
}

Viktiga alternativ att överväga:

Bästa praxis för React-komponenter med TypeScript

Typning av komponentprops

En av de viktigaste aspekterna av att använda TypeScript med React är att korrekt typa dina komponentprops. Använd gränssnitt eller typalias för att definiera formen på props-objektet.

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

const MyComponent: React.FC<MyComponentProps> = ({ name, age, onClick }) => {
  return (
    <div>
      <p>Hello, {name}!</p>
      {age && <p>You are {age} years old.</p>}
      <button onClick={onClick}>Click me</button>
    </div>
  );
};

Användning av React.FC<MyComponentProps> säkerställer att komponenten är en funktionell komponent och att propsen är korrekt typade.

Typning av komponenttillstånd

Om du använder klasskomponenter måste du också typa komponentens tillstånd. Definiera ett gränssnitt eller typalias för tillståndsobjektet och använd det i komponentdefinitionen.

interface MyComponentState {
  count: number;
}

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

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

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

För funktionella komponenter som använder useState-hooken kan TypeScript ofta härleda typen av tillståndsvariabeln, men du kan också uttryckligen ange den:

import React, { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

Använda typvakter

Typvakter är funktioner som smalnar av typen av en variabel inom ett specifikt omfång. De är användbara när man hanterar unionstyper eller när du behöver säkerställa att en variabel har en specifik typ innan du utför en operation.

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;
  }
}

Funktionen isCircle är en typvakt som kontrollerar om en Shape är en Circle. Inom if-blocket vet TypeScript att shape är en Circle och tillåter dig att komma åt dess radius-egenskap.

Hantera händelser

När du hanterar händelser i React med TypeScript är det viktigt att korrekt typa händelseobjektet. Använd den lämpliga händelsetypen från React-namnrymden.

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

  return (
    <input type="text" onChange={handleChange} />
  );
};

I det här exemplet används React.ChangeEvent<HTMLInputElement> för att typa händelseobjektet för en ändringshändelse på ett inmatningselement. Detta ger åtkomst till target-egenskapen, som är ett HTMLInputElement.

Projektstruktur

En välstrukturerad projekt är avgörande för underhållbarhet och skalbarhet. Här är en föreslagen projektstruktur för en TypeScript React-applikation:

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

Nyckelfrågor:

Använda Hooks med TypeScript

React Hooks låter dig använda tillstånd och andra React-funktioner i funktionella komponenter. TypeScript fungerar sömlöst med Hooks, vilket ger typsäkerhet och en förbättrad utvecklarupplevelse.

useState

Som visats tidigare kan du uttryckligen typa tillståndsvariabeln när du använder useState:

import React, { useState } from 'react';

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

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

useEffect

När du använder useEffect, var uppmärksam på beroende-arrayen. TypeScript kan hjälpa dig att fånga fel om du glömmer att inkludera ett beroende som används inom effekten.

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

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

  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]); // Add 'count' to the dependency array

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};

Om du utelämnar count från beroende-arrayen kommer effekten endast att köras en gång när komponenten monteras, och dokumentets titel kommer inte att uppdateras när räknaren ändras. TypeScript kommer att varna dig för detta potentiella problem.

useContext

När du använder useContext måste du tillhandahålla en typ för kontextvärdet.

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

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

const ThemeContext = createContext<ThemeContextType | undefined>(undefined);

const ThemeProvider: React.FC = ({ children }) => {
  // Implement theme logic here
  return (
    <ThemeContext.Provider value={{ theme: 'light', toggleTheme: () => {} }}>
      {children}
    </ThemeContext.Provider>
  );
};

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

  return (
    <div>
      <p>Theme: {theme}</p>
      <button onClick={toggleTheme}>Toggle Theme</button>
    </div>
  );
};

export { ThemeProvider, MyComponent };

Genom att tillhandahålla en typ för kontextvärdet säkerställer du att useContext-hooken returnerar ett värde med korrekt typ.

Testa TypeScript React-komponenter

Testning är en väsentlig del av att bygga robusta applikationer. TypeScript förbättrar testning genom att tillhandahålla typsäkerhet och förbättrad kodtäckning.

Enhetstestning

Använd testramverk som Jest och React Testing Library för att enhetstesta dina komponenter.

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

describe('MyComponent', () => {
  it('renders the component with the correct name', () => {
    render(<MyComponent name="John" />);
    expect(screen.getByText('Hello, John!')).toBeInTheDocument();
  });

  it('calls the onClick handler when the button is clicked', () => {
    const onClick = jest.fn();
    render(<MyComponent name="John" onClick={onClick} />);
    fireEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

TypeScript's typkontroll hjälper till att fånga fel i dina tester, som att skicka in felaktiga props eller använda fel händelsehanterare.

Integrationstestning

Integrationstester verifierar att olika delar av din applikation fungerar korrekt tillsammans. Använd verktyg som Cypress eller Playwright för end-to-end-testning.

Prestandaoptimering

TypeScript kan också hjälpa till med prestandaoptimering genom att fånga potentiella prestandaflaskhalsar tidigt i utvecklingsprocessen.

Memoizering

Använd React.memo för att memoizera funktionella komponenter och förhindra onödiga omritningar.

import React from 'react';

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ name }) => {
  console.log('Rendering MyComponent');
  return (
    <p>Hello, {name}!</p>
  );
};

export default React.memo(MyComponent);

React.memo kommer endast att rita om komponenten om propsen har ändrats. Detta kan avsevärt förbättra prestandan, särskilt för komplexa komponenter.

Koduppdelning

Använd dynamiska importer för att dela upp din kod i mindre delar och ladda dem vid behov. Detta kan minska den initiala laddningstiden för din applikation.

import React, { Suspense } from 'react';

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

const App: React.FC = () => {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <MyComponent />
    </Suspense>
  );
};

React.lazy låter dig dynamiskt importera komponenter, som laddas endast när de behövs. Suspense-komponenten tillhandahåller ett reservgränssnitt medan komponenten laddas.

Slutsats

Att använda TypeScript med React kan avsevärt förbättra kvaliteten, underhållbarheten och skalbarheten i dina webbapplikationer. Genom att följa dessa bästa praxis kan du utnyttja kraften i TypeScript för att bygga robusta och högpresterande applikationer som möter behoven hos en global publik. Kom ihåg att fokusera på tydliga typdefinitioner, välstrukturerad projektorganisation och noggrann testning för att säkerställa dina projekts långsiktiga framgång.

Vidare resurser