Tiếng Việt

Khám phá các phương pháp tốt nhất khi sử dụng TypeScript với React để xây dựng ứng dụng web mạnh mẽ, dễ mở rộng và bảo trì. Tìm hiểu về cấu trúc dự án, thiết kế component, kiểm thử và tối ưu hóa.

TypeScript với React: Các Phương Pháp Tốt Nhất cho Ứng Dụng Dễ Mở Rộng và Bảo Trì

TypeScript và React là một sự kết hợp mạnh mẽ để xây dựng các ứng dụng web hiện đại. TypeScript mang lại kiểu tĩnh cho JavaScript, cải thiện chất lượng và khả năng bảo trì mã nguồn, trong khi React cung cấp một cách tiếp cận khai báo và dựa trên component để xây dựng giao diện người dùng. Bài viết này khám phá các phương pháp tốt nhất khi sử dụng TypeScript với React để tạo ra các ứng dụng mạnh mẽ, dễ mở rộng và bảo trì, phù hợp với người dùng toàn cầu.

Tại sao nên sử dụng TypeScript với React?

Trước khi đi sâu vào các phương pháp tốt nhất, hãy cùng tìm hiểu tại sao TypeScript là một sự bổ sung quý giá cho việc phát triển React:

Thiết lập một dự án React với TypeScript

Sử dụng Create React App

Cách dễ nhất để bắt đầu một dự án React TypeScript mới là sử dụng Create React App với mẫu TypeScript:

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

Lệnh này thiết lập một dự án React cơ bản đã được cấu hình TypeScript, bao gồm các phụ thuộc cần thiết và tệp tsconfig.json.

Cấu hình tsconfig.json

Tệp tsconfig.json là trung tâm của cấu hình TypeScript của bạn. Dưới đây là một số cài đặt được đề xuất:

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

Các tùy chọn chính cần xem xét:

Các phương pháp tốt nhất cho Component React với TypeScript

Định kiểu cho Props của Component

Một trong những khía cạnh quan trọng nhất khi sử dụng TypeScript với React là định kiểu đúng cho props của component. Sử dụng interface hoặc type alias để định nghĩa hình dạng của đối tượng props.

interface MyComponentProps {
  name: string;
  age?: number; // Prop tùy chọn
  onClick: () => void;
}

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

Xin chào, {name}!

{age &&

Bạn {age} tuổi.

}
); };

Sử dụng React.FC<MyComponentProps> đảm bảo rằng component là một functional component và các props được định kiểu chính xác.

Định kiểu cho State của Component

Nếu bạn đang sử dụng class component, bạn cũng cần định kiểu cho state của component. Hãy định nghĩa một interface hoặc type alias cho đối tượng state và sử dụng nó trong định nghĩa component.

interface MyComponentState {
  count: number;
}

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

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

  render() {
    return (
      

Số đếm: {this.state.count}

); } }

Đối với functional component sử dụng hook useState, TypeScript thường có thể suy ra kiểu của biến state, nhưng bạn cũng có thể cung cấp nó một cách tường minh:

import React, { useState } from 'react';

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

  return (
    

Số đếm: {count}

); };

Sử dụng Type Guards

Type guards là các hàm thu hẹp kiểu của một biến trong một phạm vi cụ thể. Chúng hữu ích khi xử lý union types hoặc khi bạn cần đảm bảo một biến có một kiểu cụ thể trước khi thực hiện một thao tác.

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

Hàm isCircle là một type guard kiểm tra xem một Shape có phải là Circle không. Bên trong khối lệnh if, TypeScript biết rằng shape là một Circle và cho phép bạn truy cập thuộc tính radius của nó.

Xử lý sự kiện

Khi xử lý sự kiện trong React với TypeScript, điều quan trọng là phải định kiểu chính xác cho đối tượng sự kiện. Sử dụng kiểu sự kiện thích hợp từ không gian tên React.

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

  return (
    
  );
};

Trong ví dụ này, React.ChangeEvent<HTMLInputElement> được sử dụng để định kiểu cho đối tượng sự kiện của một sự kiện thay đổi trên một phần tử input. Điều này cung cấp quyền truy cập vào thuộc tính target, là một HTMLInputElement.

Cấu trúc dự án

Một dự án có cấu trúc tốt là rất quan trọng cho khả năng bảo trì và mở rộng. Dưới đây là một cấu trúc dự án được đề xuất cho một ứng dụng React TypeScript:

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

Các điểm chính:

Sử dụng Hooks với TypeScript

React Hooks cho phép bạn sử dụng state và các tính năng khác của React trong functional component. TypeScript hoạt động liền mạch với Hooks, cung cấp sự an toàn về kiểu và cải thiện trải nghiệm của nhà phát triển.

useState

Như đã trình bày trước đó, bạn có thể định kiểu tường minh cho biến state khi sử dụng useState:

import React, { useState } from 'react';

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

  return (
    

Số đếm: {count}

); };

useEffect

Khi sử dụng useEffect, hãy chú ý đến mảng phụ thuộc. TypeScript có thể giúp bạn phát hiện lỗi nếu bạn quên bao gồm một phụ thuộc được sử dụng bên trong effect.

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

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

  useEffect(() => {
    document.title = `Số đếm: ${count}`;
  }, [count]); // Thêm 'count' vào mảng phụ thuộc

  return (
    

Số đếm: {count}

); };

Nếu bạn bỏ qua count khỏi mảng phụ thuộc, effect sẽ chỉ chạy một lần khi component được gắn kết, và tiêu đề tài liệu sẽ không cập nhật khi số đếm thay đổi. TypeScript sẽ cảnh báo bạn về vấn đề tiềm ẩn này.

useContext

Khi sử dụng useContext, bạn cần cung cấp một kiểu cho giá trị context.

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

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

const ThemeContext = createContext(undefined);

const ThemeProvider: React.FC = ({ children }) => {
  // Triển khai logic theme tại đây
  return (
     {} }}>
      {children}
    
  );
};

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

  return (
    

Theme: {theme}

); }; export { ThemeProvider, MyComponent };

Bằng cách cung cấp một kiểu cho giá trị context, bạn đảm bảo rằng hook useContext trả về một giá trị với kiểu chính xác.

Kiểm thử Component React TypeScript

Kiểm thử là một phần thiết yếu của việc xây dựng các ứng dụng mạnh mẽ. TypeScript tăng cường việc kiểm thử bằng cách cung cấp sự an toàn về kiểu và cải thiện phạm vi bao phủ mã.

Kiểm thử đơn vị (Unit Testing)

Sử dụng các framework kiểm thử như Jest và React Testing Library để kiểm thử đơn vị các component của bạn.

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

describe('MyComponent', () => {
  it('hiển thị component với tên chính xác', () => {
    render();
    expect(screen.getByText('Xin chào, John!')).toBeInTheDocument();
  });

  it('gọi trình xử lý onClick khi nút được nhấp', () => {
    const onClick = jest.fn();
    render();
    fireEvent.click(screen.getByRole('button'));
    expect(onClick).toHaveBeenCalledTimes(1);
  });
});

Việc kiểm tra kiểu của TypeScript giúp phát hiện lỗi trong các bài kiểm thử của bạn, chẳng hạn như truyền props không chính xác hoặc sử dụng các trình xử lý sự kiện sai.

Kiểm thử tích hợp (Integration Testing)

Kiểm thử tích hợp xác minh rằng các phần khác nhau của ứng dụng của bạn hoạt động chính xác với nhau. Sử dụng các công cụ như Cypress hoặc Playwright để kiểm thử end-to-end.

Tối ưu hóa hiệu suất

TypeScript cũng có thể giúp tối ưu hóa hiệu suất bằng cách phát hiện các điểm nghẽn hiệu suất tiềm ẩn sớm trong quá trình phát triển.

Ghi nhớ (Memoization)

Sử dụng React.memo để ghi nhớ các functional component và ngăn chặn các lần render lại không cần thiết.

import React from 'react';

interface MyComponentProps {
  name: string;
}

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

Xin chào, {name}!

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

React.memo sẽ chỉ render lại component nếu props đã thay đổi. Điều này có thể cải thiện đáng kể hiệu suất, đặc biệt là đối với các component phức tạp.

Tách mã (Code Splitting)

Sử dụng dynamic import để chia mã của bạn thành các đoạn nhỏ hơn và tải chúng theo yêu cầu. Điều này có thể giảm thời gian tải ban đầu của ứng dụng.

import React, { Suspense } from 'react';

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

const App: React.FC = () => {
  return (
    Đang tải...
}> ); };

React.lazy cho phép bạn nhập động các component, chúng chỉ được tải khi cần thiết. Component Suspense cung cấp một giao diện người dùng dự phòng trong khi component đang tải.

Kết luận

Sử dụng TypeScript với React có thể cải thiện đáng kể chất lượng, khả năng bảo trì và khả năng mở rộng của các ứng dụng web của bạn. Bằng cách tuân theo các phương pháp tốt nhất này, bạn có thể tận dụng sức mạnh của TypeScript để xây dựng các ứng dụng mạnh mẽ và hiệu suất cao, đáp ứng nhu cầu của người dùng toàn cầu. Hãy nhớ tập trung vào các định nghĩa kiểu rõ ràng, tổ chức dự án có cấu trúc tốt và kiểm thử kỹ lưỡng để đảm bảo sự thành công lâu dài của các dự án của bạn.

Tài liệu tham khảo thêm

TypeScript với React: Các Phương Pháp Tốt Nhất cho Ứng Dụng Dễ Mở Rộng và Bảo Trì | MLOG