手记

React+TS项目实战:新手入门到简单应用

概述

本文将详细介绍如何在React项目中引入TypeScript,从集成TypeScript开始,逐步构建一个简单的待办事项应用,演示数据流管理和组件使用TypeScript进行类型定义的方法,最终完成一个实用的React+TS项目实战。

React基础概述
React简介

React 是一个由 Facebook 开发和维护的 JavaScript 库,用于构建用户界面,特别是单页面应用的用户界面。React 的核心设计理念是将用户界面分解为可重用的组件,每个组件负责一部分界面的渲染和行为。通过这种方式,React 能够提高开发效率,增强代码的可维护性,并通过虚拟 DOM 机制提高应用的性能。

React的核心概念

React 的核心概念主要包括组件、状态(State)、属性(Props)、生命周期方法等。

组件

组件是 React 中最基本最核心的概念。组件可以理解为一个可重用的用户界面代码片段,它负责渲染特定的用户界面并响应用户交互。组件可以嵌套在其他组件内部,这使得代码结构更加清晰,易于维护。

状态(State)

状态是用来存储组件内部的数据,当状态发生变化时,组件会重新渲染。状态是组件内部私有的,只能通过组件内部的方法来修改。

属性(Props)

属性是组件之间传递数据的一种方式,它允许父组件向子组件传递数据。子组件可以通过 props 属性接收数据,然后使用这些数据来渲染组件。例如,父组件传递一个字符串给子组件:

// 父组件
function ParentComponent() {
  return <ChildComponent message="Hello from Parent" />;
}

// 子组件
function ChildComponent({ message }) {
  return <p>{message}</p>;
}

生命周期方法

生命周期方法允许开发者在组件的不同阶段执行特定的操作,如初始化、渲染、更新、销毁等。生命周期方法可以帮助开发者更好地控制组件的行为和优化性能。

创建第一个React项目

要创建一个新的 React 项目,可以使用 create-react-app 工具,这是一个由 Facebook 提供的官方脚手架工具,它能够快速地搭建一个新的 React 应用。

安装 create-react-app

首先,确保你已经安装了 Node.js 和 npm。然后,使用 npm 安装 create-react-app

npx create-react-app my-app
cd my-app
npm start

项目结构

创建项目后,目录结构如下:

my-app/
├── node_modules/
├── public/
│   ├── index.html
│   └── favicon.ico
├── src/
│   ├── index.css
│   ├── index.js
│   ├── App.css
│   └── App.js
├── package.json
└── README.md

src 目录是项目的主要开发目录,App.jsindex.js 文件是项目的入口点。

编写第一个组件

下面是一个简单的组件示例,它展示了一个按钮:

// src/App.js
import React from 'react';

function Button() {
  return (
    <button>
      点我
    </button>
  );
}

export default Button;

index.js 文件中,你可以将这个组件添加到应用的根组件中:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

现在,运行 npm start 命令,就可以看到一个按钮出现在浏览器中。

TypeScript基础介绍
TypeScript简介

TypeScript 是 JavaScript 的一个超集,它在 JavaScript 的基础上增加了静态类型检查功能。TypeScript 的类型系统有助于提高代码的可读性和可维护性,同时减少了运行时错误的发生。

安装并配置TypeScript

要使用 TypeScript,首先需要安装 TypeScript 编译器。可以通过 npm 来全局安装 TypeScript:

npm install -g typescript

然后,可以在你的项目中安装 TypeScript:

npm install --save-dev typescript

接下来,创建一个 tsconfig.json 文件,该文件包含了 TypeScript 编译器需要的各种配置信息。

npx tsc --init

tsconfig.json 文件

tsconfig.json 文件是一个配置文件,它包含了 TypeScript 编译器需要的各种选项。下面是一个简单的 tsconfig.json 配置示例:

{
  "compilerOptions": {
    "target": "ES6",
   .
    .
    .
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["node_modules", "dist"]
}
基本语法与类型推断

TypeScript 提供了丰富的类型系统,类型可以用于变量、函数、类等。TypeScript 能够自动推断类型,这意味着你不需要在所有情况下都手动指定类型。

变量与类型

TypeScript 中的变量可以显式地指定类型,也可以通过类型推断自动推断类型。

let age: number = 25;
let name: string = 'Alice';
let isStudent: boolean = true;

// 自动类型推断
let age2 = 25; // 类型推断为 number
let name2 = 'Bob'; // 类型推断为 string
let isStudent2 = false; // 类型推断为 boolean

函数类型

在 TypeScript 中,可以为函数的参数和返回值指定类型。

function add(a: number, b: number): number {
  return a + b;
}

// 声明函数类型
type AddFunction = (a: number, b: number) => number;

let add2: AddFunction = (a: number, b: number) => a + b;

// 也可以用函数类型定义
function add3(a: number, b: number): number {
  return a + b;
}

// 使用参数类型
function logMessage(message: string): void {
  console.log(message);
}

类型别名与接口

类型别名和接口都可以用来定义复杂的数据结构。

// 类型别名
type Point = {
  x: number;
  y: number;
};

// 接口定义
interface Rectangle {
  width: number;
  height: number;
}

let rect: Rectangle = {
  width: 10,
  height: 20
};
React项目中引入TypeScript
在现有React项目中集成TypeScript

要在现有 React 项目中集成 TypeScript,需要进行以下步骤:

  1. 安装 TypeScript 相关依赖
  2. 将项目中的 .js 文件改为 .ts.tsx
  3. 配置 tsconfig.json 文件

安装 TypeScript 相关依赖

你可以在项目中安装 TypeScript 以及一些必要的类型定义:

npm install --save-dev typescript @types/node @types/react @types/react-dom

修改文件后缀

将项目中的 .js 文件改为 .ts.tsx。例如,将 App.js 改为 App.tsx:

mv src/App.js src/App.tsx

配置 tsconfig.json 文件

编辑 tsconfig.json 文件,确保 TypeScript 编译器知道如何正确编译你的 React 项目。

{
  "compilerOptions": {
    "target": "ES6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "outDir": "./dist",
    "jsx": "react"
  },
  "include": ["src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["node_modules", "dist"]
}
配置tsconfig.json文件

tsconfig.json 文件中的一些关键配置项包括:

  • target: 指定生成的代码的目标 ECMAScript 版本。
  • module: 指定生成的模块系统。对于 React 项目,通常使用 commonjs
  • strict: 启用严格的类型检查。
  • jsx: 设置为 react 表示生成的代码会包含 JSX。
常见TypeScript类型与接口定义

在 React 项目中,常见的 TypeScript 类型包括 string, number, boolean, object, Array, Function 等。此外,React 组件的属性和状态也通常通过接口来定义。

定义接口

接口可以用来描述组件的属性类型和状态类型。

interface Props {
  message: string;
  count: number;
}

interface State {
  isActive: boolean;
}

组件示例

下面是一个使用 TypeScript 的 React 组件示例:

// src/App.tsx
import React, { Component, ReactElement } from 'react';

interface Props {
  message: string;
}

interface State {
  count: number;
}

class App extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render(): ReactElement {
    return (
      <div>
        <h1>{this.props.message}</h1>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment
        </button>
      </div>
    );
  }
}

export default App;
构建简单的React+TS应用
创建组件并使用TypeScript

在 React+TS 项目中,创建组件和使用 TypeScript 类似于普通的 React 组件,但通过类型定义可以提供更强的类型检查。

示例组件

下面是一个简单的 TypeScript React 组件,它包含一个输入框和一个按钮:

// src/components/InputComponent.tsx
import React, { Component, ReactElement } from 'react';

interface Props {
  message: string;
}

interface State {
  value: string;
}

class InputComponent extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      value: ''
    };
  }

  handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    this.setState({ value: event.target.value });
  };

  render(): ReactElement {
    return (
      <div>
        <input
          type="text"
          value={this.state.value}
          onChange={this.handleChange}
        />
        <p>{this.state.value}</p>
      </div>
    );
  }
}

export default InputComponent;
管理状态与生命周期方法

在 React+TS 中,可以使用类组件来管理状态和生命周期方法。通常,状态使用 state 属性来定义,生命周期方法则通过类的生命周期钩子来实现。

示例:管理状态

下面是一个示例,展示如何在类组件中管理状态:

// src/components/CounterComponent.tsx
import React, { Component, ReactElement } from 'react';

interface Props {}

interface State {
  count: number;
}

class CounterComponent extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  increment = () => {
    this.setState((prevState) => ({
      count: prevState.count + 1
    }));
  };

  decrement = () => {
    this.setState((prevState) => ({
      count: prevState.count - 1
    }));
  };

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

export default CounterComponent;
数据流管理与通信

在 React 中,数据流通常是从父组件流向子组件。父组件将数据通过 props 传递给子组件,子组件则可以使用这些数据进行渲染。

示例:父组件向子组件传递数据

下面是一个父组件向子组件传递数据的示例:

// src/components/ParentComponent.tsx
import React, { Component, ReactElement } from 'react';
import ChildComponent from './ChildComponent';

interface Props {}

interface State {
  message: string;
}

class ParentComponent extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      message: 'Hello from Parent'
    };
  }

  render(): ReactElement {
    return (
      <div>
        <ChildComponent message={this.state.message} />
      </div>
    );
  }
}

export default ParentComponent;
// src/components/ChildComponent.tsx
import React, { Component, ReactElement } from 'react';

interface Props {
  message: string;
}

class ChildComponent extends Component<Props, {}> {
  render(): ReactElement {
    return (
      <p>
        {this.props.message}
      </p>
    );
  }
}

export default ChildComponent;
项目实践:开发一个简单的待办事项应用
功能需求分析

待办事项应用是一个简单的应用,它允许用户添加、编辑和删除待办事项。具体功能包括:

  • 添加新的待办事项
  • 显示所有待办事项
  • 标记待办事项为完成或未完成
  • 删除待办事项
构建应用界面与交互逻辑

为了构建待办事项应用,我们需要创建几个组件来表示不同的功能。我们可以将应用分为以下几个主要组件:

  • App:应用的根组件,包含主应用逻辑。
  • TodoList:显示待办事项列表。
  • TodoItem:表示单个待办事项。
  • TodoForm:添加新的待办事项。

根组件 App

根组件负责管理状态和协调各个子组件:

// src/App.tsx
import React, { Component, ReactElement } from 'react';
import TodoList from './TodoList';
import TodoForm from './TodoForm';

interface Props {}

interface State {
  todos: Todo[];
}

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

class App extends Component<Props, State> {
  constructor(props: Props) {
    super(props);
    this.state = {
      todos: []
    };
  }

  addTodo = (text: string) => {
    const newTodo: Todo = {
      id: Date.now(),
      text,
      completed: false
    };
    this.setState((prevState) => ({
      todos: [...prevState.todos, newTodo]
    }));
  };

  toggleTodo = (id: number) => {
    this.setState((prevState) => ({
      todos: prevState.todos.map((todo) =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    }));
  };

  removeTodo = (id: number) => {
    this.setState((prevState) => ({
      todos: prevState.todos.filter((todo) => todo.id !== id)
    }));
  };

  render(): ReactElement {
    return (
      <div>
        <h1>待办事项应用</h1>
        <TodoForm onAddTodo={this.addTodo} />
        <TodoList
          todos={this.state.todos}
          onToggleTodo={this.toggleTodo}
          onRemoveTodo={this.removeTodo}
        />
      </div>
    );
  }
}

export default App;

显示待办事项列表组件 TodoList

TodoList 组件负责渲染待办事项列表,并调用 toggleTodoremoveTodo 方法来处理用户交互。

// src/components/TodoList.tsx
import React, { Component, ReactElement } from 'react';
import TodoItem from './TodoItem';

interface Props {
  todos: Todo[];
  onToggleTodo: (id: number) => void;
  onRemoveTodo: (id: number) => void;
}

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

class TodoList extends Component<Props, {}> {
  render(): ReactElement {
    return (
      <ul>
        {this.props.todos.map((todo) => (
          <TodoItem
            key={todo.id}
            todo={todo}
            onToggle={this.props.onToggleTodo}
            onRemove={this.props.onRemoveTodo}
          />
        ))}
      </ul>
    );
  }
}

export default TodoList;

单个待办事项组件 TodoItem

TodoItem 组件表示单个待办事项,它会处理标记任务为完成或未完成,以及删除任务的操作。

// src/components/TodoItem.tsx
import React, { Component, ReactElement } from 'react';

interface Props {
  todo: Todo;
  onToggle: (id: number) => void;
  onRemove: (id: number) => void;
}

interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

class TodoItem extends Component<Props, {}> {
  render(): ReactElement {
    const { todo, onToggle, onRemove } = this.props;

    return (
      <li>
        <input
          type="checkbox"
          checked={todo.completed}
          onChange={() => onToggle(todo.id)}
        />
        <span>{todo.text}</span>
        <button onClick={() => onRemove(todo.id)}>删除</button>
      </li>
    );
  }
}

export default TodoItem;

添加待办事项表单组件 TodoForm

TodoForm 组件负责接收用户输入并调用 addTodo 方法来添加新的待办事项。

// src/components/TodoForm.tsx
import React, { Component, ReactElement } from 'react';

interface Props {
  onAddTodo: (text: string) => void;
}

class TodoForm extends Component<Props, {}> {
  state = {
    text: ''
  };

  handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    this.setState({ text: event.target.value });
  };

  handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();
    this.props.onAddTodo(this.state.text);
    this.setState({ text: '' });
  };

  render(): ReactElement {
    return (
      <form onSubmit={this.handleSubmit}>
        <input
          type="text"
          value={this.state.text}
          onChange={this.handleChange}
          placeholder="添加待办事项"
        />
        <button type="submit">添加</button>
      </form>
    );
  }
}

export default TodoForm;
测试与调试

在开发过程中,需要经常测试代码以确保它按预期工作。可以使用浏览器的开发者工具或者使用 Jest 和 React Testing Library 进行单元测试和集成测试。

使用 Jest 和 React Testing Library 进行测试

首先,安装 Jest 和 React Testing Library:

npm install --save-dev jest @testing-library/react @testing-library/jest-dom

然后,编写测试用例:

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

test('TodoItem renders correctly', () => {
  const todo = { id: 1, text: 'Test Todo', completed: false };
  const { getByText } = render(<TodoItem todo={todo} onToggle={() => {}} onRemove={() => {}} />);
  expect(getByText('Test Todo')).toBeInTheDocument();
});

test('TodoItem toggles completion', () => {
  const todo = { id: 1, text: 'Test Todo', completed: false };
  const toggle = jest.fn();
  const { getByRole } = render(<TodoItem todo={todo} onToggle={toggle} onRemove={() => {}} />);
  fireEvent.click(getByRole('checkbox'));
  expect(toggle).toHaveBeenCalledWith(1);
});

test('TodoItem removes todo', () => {
  const todo = { id: 1, text: 'Test Todo', completed: false };
  const remove = jest.fn();
  const { getByText } = render(<TodoItem todo={todo} onToggle={() => {}} onRemove={remove} />);
  fireEvent.click(getByText('删除'));
  expect(remove).toHaveBeenCalledWith(1);
});
项目部署与发布
构建生产环境的项目

要构建生产环境的项目,可以使用 npm run build 命令。这个命令会使用 Webpack 打包应用,并生成优化的生产代码。

npm run build

构建后,生成的代码会被放置在 build 目录中。

部署到Web服务器

可以使用 Web 服务器来部署生成的代码。例如,使用 Nginx 来部署:

  1. 安装 Nginx
  2. 配置 Nginx
  3. 启动 Nginx
sudo apt-get update
sudo apt-get install nginx
sudo nano /etc/nginx/sites-available/default

在 Nginx 配置文件中,添加以下内容:

server {
    listen 80;
    server_name yourdomain.com;

    root /path/to/your/build;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }
}

保存并退出,然后重启 Nginx:

sudo systemctl restart nginx
应用监控与维护

部署后,可以使用各种工具来监控应用的运行情况。例如,可以使用 PM2 来管理应用进程,并使用 PrometheusGrafana 来收集和展示监控数据。

使用 PM2 管理进程

安装 PM2:

npm install pm2 -g

然后,启动应用:

pm2 start /path/to/your/build/server.js --name your-app
pm2 save
pm2 startup
pm2 start ecosystem.config.js

使用 Prometheus 和 Grafana 监控

安装 Prometheus:

wget -q https://github.com/prometheus/prometheus/releases/download/v2.30.3/prometheus-2.30.3.linux-amd64.tar.gz
tar xvf prometheus-2.30.3.linux-amd64.tar.gz
cd prometheus-2.30.3.linux-amd64
./prometheus --web.enable-lifecycle --config.file=prometheus.yml --storage.tsdb.path=.

安装 Grafana:

wget https://dl.grafana.com/oss/release/grafana-8.3.1-amd64.deb
sudo dpkg -i grafana-8.3.1-amd64.deb
sudo service grafana-server start

配置 Prometheus 以抓取应用的监控数据,并在 Grafana 中设置仪表板来展示这些数据。

0人推荐
随时随地看视频
慕课网APP