继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

React+typescrip项目实战:从入门到小项目实践

吃鸡游戏
关注TA
已关注
手记 485
粉丝 55
获赞 339
概述

本文详细介绍了如何使用React和TypeScript创建和部署一个完整的项目,涵盖了从项目结构、组件开发、状态管理到路由配置的全过程。文章通过具体示例展示了如何在React组件中利用TypeScript增强类型安全,并提供了部署项目到GitHub Pages的详细步骤,确保项目在生产环境中的顺利运行。

React与TypeScript基础
React简介

React 是一个由 Facebook 开发并维护的 JavaScript 库,用于构建用户界面。它提供了一种构建可重用组件的方法,这些组件可以组合成复杂的 UI 层,同时保持高效和可维护。

React的主要特点

  • 组件化:通过组件化开发,可以将功能相似的代码封装成可重用的组件。
  • 虚拟DOM:通过对比真实DOM和虚拟DOM之间的差异,提高更新效率。
  • 单向数据流:数据从父组件流向子组件,保证了数据的单向流动。
  • JSX:JSX 是 JavaScript 和 XML 的结合,允许在 JavaScript 文件中书写类似 HTML 的代码,提供了一种清晰的模板语法。

React的安装

可以使用 npm 或 yarn 来安装 React。以下是使用 npm 安装的示例:

npm install react react-dom
TypeScript简介

TypeScript 是由 Microsoft 开发的一种开源编程语言,它是 JavaScript 的超集,添加了静态类型检查和更多的类型特性。TypeScript 可以帮助开发者减少运行时错误,提高代码的可读性和可维护性。

TypeScript的主要特点

  • 静态类型检查:允许在编译时发现类型错误。
  • 类和接口:支持类、接口等面向对象编程特性。
  • 泛型:提供了一种类型安全的方式来编写可重用的代码。
  • 模块化:支持 ES6 模块系统,使得代码更易于管理和复用。
  • 支持多种环境:可以在各种环境中使用,包括浏览器、服务器、桌面应用等。

TypeScript的安装

可以使用 npm 或 yarn 来安装 TypeScript。以下是使用 npm 安装的示例:

npm install typescript --save-dev
创建第一个React+TypeScript项目

要创建一个 React+TypeScript 项目,可以使用 Create React App,这是一个官方的脚手架工具,简化了 React 应用的开发。

创建项目

首先,确保已经安装了 Node.js 和 npm。然后可以通过以下命令来创建一个新的 React+TypeScript 项目:

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

此命令会创建一个名为 my-app 的文件夹,其中包含了完整的 React+TypeScript 项目结构。

项目结构

创建项目后,进入项目目录并查看文件结构:

cd my-app
ls

项目的基本结构如下:

my-app/
├── node_modules/
├── public/
├── src/
├── .gitignore
├── package.json
├── tsconfig.json
├── package-lock.json
└── README.md
  • node_modules/:安装的依赖包。
  • public/:包含 HTML 和静态资源文件。
  • src/:存放源代码,包括组件和样式文件。
  • tsconfig.json:TypeScript 配置文件。
  • package.json:项目依赖和脚本配置。
  • README.md:项目说明文件。

运行项目

在项目根目录下运行以下命令来启动开发服务器:

npm start

这会启动一个开发服务器,并在浏览器中打开 http://localhost:3000/,可以查看项目的运行效果。

代码示例

src/App.tsx 文件中可以看到初始的 App 组件,这是一个典型的 React 组件:

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

这个示例展示了如何使用 JSX 语法和 TypeScript 语法共同编写 React 组件。

React组件开发与TypeScript类型声明
组件的基本概念

React 组件是构成应用的基本单元,每个组件都可以分为两部分:逻辑部分(JavaScript 代码)和渲染部分(JSX 代码)。组件可以接收输入(通过 props),可以拥有内部状态(通过 state),并可以返回用于渲染的 JSX 代码。

组件的分类

  • 函数组件:简单的功能组件,使用函数来定义。
  • 类组件:功能更强大的组件,可以使用生命周期方法,可以通过继承 React.Component 来定义。

创建一个简单的组件

import React from 'react';

interface Props {
  name: string;
}

function Greeting(props: Props) {
  return <h1>Hello, {props.name}</h1>;
}

export default Greeting;

在这个示例中,Greeting 是一个函数组件,它接受一个包含 name 属性的对象作为 props,并返回一个 JSX 代码用于渲染。

使用TypeScript为React组件添加类型声明

使用 TypeScript 为 React 组件添加类型声明可以提高代码的可读性和可维护性。

定义组件的属性类型

可以使用 TypeScript 的接口来定义组件的属性类型:

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

function Display(props: Props) {
  return (
    <div>
      <h1>{props.title}</h1>
      <p>Count: {props.count}</p>
    </div>
  );
}

// 使用组件
const App = () => {
  return <Display title="Hello" count={5} />;
};

定义组件的状态类型

同样,可以使用 TypeScript 定义组件的状态类型:

interface AppState {
  message: string;
}

class Message extends React.Component<{}, AppState> {
  constructor(props: {}) {
    super(props);
    this.state = { message: 'Hello, TypeScript!' };
  }

  render() {
    return <h1>{this.state.message}</h1>;
  }
}

export default Message;

在这个示例中,Message 组件的状态类型被定义为 AppState

通过例子理解props和state类型

props 的类型声明

import React from 'react';

interface Props {
  name: string;
  age?: number; // 可选属性
}

function Profile(props: Props) {
  return (
    <div>
      <h1>Name: {props.name}</h1>
      {props.age && <p>Age: {props.age}</p>}
    </div>
  );
}

const App = () => {
  return (
    <div>
      <Profile name="John Doe" />
      <Profile name="Jane Doe" age={25} />
    </div>
  );
};

export default App;

在这个示例中,Profile 组件接收一个 name 属性,以及一个可选的 age 属性。

state 的类型声明

import React, { useState } from 'react';

interface State {
  count: number;
}

function Counter() {
  const [state, setState] = useState<State>({ count: 0 });

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

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

export default Counter;

在这个示例中,Counter 组件的状态类型被定义为 State,并通过 useState 钩子来管理状态。

状态管理和事件处理
状态管理基础

React 组件有两种状态:props 和 state。Props 是从父组件传递给子组件的属性,而 state 是组件内部的状态,用于在组件内部保存和管理数据。

state 的使用

import React, { Component } from 'react';

interface AppState {
  count: number;
}

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

  componentDidMount() {
    this.setState({ count: 1 });
  }

  render() {
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
      </div>
    );
  }
}

export default Counter;

在这个示例中,Counter 组件在初始化时将 count 设置为 0,然后在组件挂载完成时通过 componentDidMount 生命周期方法将 count 设置为 1。

抛出新的 state

React 提供了 setState 方法来更新组件的状态。setState 是异步的,这意味着它可能会延迟执行,以避免不必要的重新渲染。

this.setState((state, props) => {
  return { count: state.count + 1 };
});

state 的合并

使用 setState 时,React 会自动合并新的状态对象。这意味着你可以直接传递一个对象来更新状态,而不需要关心之前的值。

事件处理简介

React 中的事件和 DOM 事件非常相似,但语法略有不同。React 使用驼峰命名法来命名事件,例如 onClick 而不是 onclick

事件处理函数

import React from 'react';

function Counter() {
  const [count, setCount] = React.useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

export default Counter;

在这个示例中,Counter 组件定义了一个 handleClick 函数来处理按钮的点击事件,并通过 setState 更新状态。

事件对象

React 传递一个合成事件对象给事件处理函数,该对象继承自标准的浏览器事件对象。可以通过 e.target 访问触发事件的目标元素。

function Input() {
  const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    console.log(e.target.value);
  };

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

export default Input;

在这个示例中,Input 组件定义了一个 handleChange 函数来处理输入框的 onChange 事件,并通过 e.target.value 获取输入框的值。

实践:创建一个简单的计数器组件

实现计数器组件

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  const decrement = () => {
    setCount(count - 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
      <button onClick={decrement}>Decrement</button>
    </div>
  );
}

export default Counter;

在这个示例中,Counter 组件使用 useState 钩子来管理 count 状态,并定义了两个事件处理函数 incrementdecrement 来更新状态。

运行计数器组件

Counter 组件添加到 App.tsx 中并运行项目。

import React from 'react';
import Counter from './Counter';

function App() {
  return (
    <div>
      <Counter />
    </div>
  );
}

export default App;
高阶组件与Hooks
高阶组件的应用场景

高阶组件(Higher-Order Component, HOC)是一种高级的 React 组件模式,它通过将组件作为参数传递给一个函数来返回一个新的组件。HOC 可以用来复用组件逻辑,例如,抽取出组件的公共逻辑或者用于组件的增强。

使用 HOC

import React from 'react';

function withLogging(WrappedComponent: React.ComponentType) {
  return function EnhancedComponent(props) {
    console.log('EnhancedComponent rendered');
    return <WrappedComponent {...props} />;
  };
}

const LoggedButton = withLogging(Button);

function Button(props) {
  return (
    <button {...props}>
      {props.children}
    </button>
  );
}

export default LoggedButton;

在这个示例中,withLogging 是一个高阶组件,它接收一个组件作为参数,并返回一个增强后的组件。

使用Hooks简化状态管理

React Hooks 是一种新的机制,它允许你在不编写类的情况下使用状态和其他 React 特性。Hooks 使得函数组件可以访问之前只能在类组件中提供的功能。

useState Hook

useState Hook 可以在函数组件中定义简单的状态。

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

在这个示例中,Counter 组件使用 useState Hook 来定义和更新状态。

useEffect Hook

useEffect Hook 可以用来执行副作用操作,例如订阅、定时器、设置或删除 DOM 元素等。

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

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={increment}>Increment</button>
    </div>
  );
}

export default Counter;

在这个示例中,Counter 组件使用 useEffect Hook 在 count 发生变化时更新文档标题。

实践:使用useState和useEffect构建动态数据加载组件

动态数据加载组件

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

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('https://api.example.com/data')
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      })
      .catch((error) => {
        console.error('Error fetching data:', error);
        setLoading(false);
      });
  }, []);

  if (loading) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>Data: {JSON.stringify(data)}</h1>
    </div>
  );
}

export default DataFetcher;

在这个示例中,DataFetcher 组件使用 useStateuseEffect Hook 来加载和显示数据。

运行数据加载组件

DataFetcher 组件添加到 App.tsx 中并运行项目。

import React from 'react';
import DataFetcher from './DataFetcher';

function App() {
  return (
    <div>
      <DataFetcher />
    </div>
  );
}

export default App;
路由与状态共享
React Router简介

React Router 是一个用于 React 应用的路由包。它允许应用根据不同的路径显示不同的组件,从而实现多页面应用的功能。

安装 React Router

npm install react-router-dom

基础使用

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <h2>About</h2>
          </Route>
          <Route path="/users">
            <h2>Users</h2>
          </Route>
          <Route path="/">
            <h2>Home</h2>
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

在这个示例中,App 组件使用 BrowserRouter 来定义路由,并通过 Link 组件来导航到不同的页面。

使用组件渲染路由

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Users from './Users';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/">
            <Home />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

在这个示例中,不同的路由路径会渲染不同的组件。

路由参数

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link, useParams } from 'react-router-dom';

function User() {
  const { id } = useParams<{ id: string }>();
  return <h2>User: {id}</h2>;
}

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/user/1">User 1</Link>
            </li>
            <li>
              <Link to="/user/2">User 2</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route path="/user/:id">
            <User />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

在这个示例中,User 组件通过 useParams Hook 获取 URL 参数。

实现简单的多页面应用

多页面应用

import React from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import Home from './Home';
import About from './About';
import Users from './Users';
import User from './User';

function App() {
  return (
    <Router>
      <div>
        <nav>
          <ul>
            <li>
              <Link to="/">Home</Link>
            </li>
            <li>
              <Link to="/about">About</Link>
            </li>
            <li>
              <Link to="/users">Users</Link>
            </li>
          </ul>
        </nav>

        <Switch>
          <Route exact path="/">
            <Home />
          </Route>
          <Route path="/about">
            <About />
          </Route>
          <Route path="/users">
            <Users />
          </Route>
          <Route path="/user/:id">
            <User />
          </Route>
        </Switch>
      </div>
    </Router>
  );
}

export default App;

在这个示例中,App 组件定义了一个多页面应用,包含首页、关于页、用户列表页和用户详情页。

状态共享与管理

状态共享是多页面应用中常见的问题。React Router 提供了一些方法来共享状态,例如通过 history 对象或者通过 useContext 钩子。

使用 Context 提供全局状态

import React, { createContext, useState, useContext } from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

const AppContext = createContext({ count: 0 });

function CountProvider({ children }) {
  const [count, setCount] = useState(0);

  return (
    <AppContext.Provider value={{ count, setCount }}>
      {children}
    </AppContext.Provider>
  );
}

function CountConsumer({ children }) {
  const context = useContext(AppContext);

  return children(context.count, context.setCount);
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Users() {
  return <h2>Users</h2>;
}

function User() {
  const [count, setCount] = useContext(AppContext);
  return <h2>User: {count}</h2>;
}

function App() {
  return (
    <Router>
      <CountProvider>
        <div>
          <nav>
            <ul>
              <li>
                <Link to="/">Home</Link>
              </li>
              <li>
                <Link to="/about">About</Link>
              </li>
              <li>
                <Link to="/users">Users</Link>
              </li>
              <li>
                <Link to="/user/1">User 1</Link>
              </li>
            </ul>
          </nav>

          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
            <Route path="/users" component={Users} />
            <Route path="/user/:id">
              <CountConsumer>
                {(count, setCount) => <User count={count} />}
              </CountConsumer>
            </Route>
          </Switch>
        </div>
      </CountProvider>
    </Router>
  );
}

export default App;

在这个示例中,CountProviderCountConsumer 通过 Context API 来共享状态。

使用 React Context API

React Context API 用于管理全局状态,可以避免在组件树中手动传递 props。

import React, { createContext, useState, useContext } from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';

const AppContext = createContext({ count: 0 });

function CountProvider({ children }) {
  const [count, setCount] = useState(0);

  return (
    <AppContext.Provider value={{ count, setCount }}>
      {children}
    </AppContext.Provider>
  );
}

function CountConsumer({ children }) {
  const context = useContext(AppContext);

  return children(context.count, context.setCount);
}

function Home() {
  return <h2>Home</h2>;
}

function About() {
  return <h2>About</h2>;
}

function Users() {
  return <h2>Users</h2>;
}

function User() {
  const context = useContext(AppContext);
  return <h2>User: {context.count}</h2>;
}

function App() {
  return (
    <Router>
      <CountProvider>
        <div>
          <nav>
            <ul>
              <li>
                <Link to="/">Home</Link>
              </li>
              <li>
                <Link to="/about">About</Link>
              </li>
              <li>
                <Link to="/users">Users</Link>
              </li>
              <li>
                <Link to="/user/1">User 1</Link>
              </li>
            </ul>
          </nav>

          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
            <Route path="/users" component={Users} />
            <Route path="/user/:id" component={User} />
          </Switch>
        </div>
      </CountProvider>
    </Router>
  );
}

export default App;

在这个示例中,CountProviderCountConsumer 通过 Context API 来共享状态。

项目部署与调试
项目打包与部署

打包项目

要打包项目,可以使用 npm run build 命令:

npm run build

这会在 build 目录中生成一个生产环境版本的项目。

部署到GitHub Pages

GitHub Pages 是一个静态网站托管服务,可以将打包后的项目部署到 GitHub 仓库的 gh-pages 分支。

  1. 创建 gh-pages 分支

    git checkout -b gh-pages
  2. 配置 package.json

    package.json 中添加以下脚本:

    "scripts": {
     "deploy": "gh-pages -d build"
    }

    这里使用了 gh-pages 工具来将 build 目录的内容部署到 gh-pages 分支。

  3. 安装 gh-pages

    npm install gh-pages --save-dev
  4. 部署项目

    npm run deploy

    这会将 build 目录的内容推送到 gh-pages 分支。

部署到其他平台

除了 GitHub Pages,还可以将项目部署到其他静态网站托管平台,例如 Netlify 或 Vercel。这些平台提供了类似的部署命令,可以方便地将项目部署到线上。

常见问题与调试技巧

问题一:打包后样式丢失

如果在打包后发现样式丢失,可以检查是否为 CSS 文件添加了正确的路径。在 public/index.html 文件中,确保引入了正确的 CSS 文件。如果使用 CSS 模块,确保 CSS 文件路径正确。

问题二:开发环境和生产环境不一致

在开发环境中,可能会使用环境变量来配置一些特定的值,例如 API 地址。在生产环境中,确保这些环境变量被正确地设置,可以通过 .env 文件来管理这些变量。

问题三:打包后文件过大

如果打包后的文件过大,可以通过优化代码和资源来减小文件大小。可以使用压缩工具对 JavaScript 和 CSS 文件进行压缩,使用 Webpack 的 tree-shaking 功能去除未使用的代码。

调试技巧

  • 使用浏览器开发者工具:浏览器的开发者工具可以查看和调试代码,包括控制台输出、网络请求、DOM 操作等。
  • 断点调试:在代码中设置断点,可以查看变量的值和函数的调用栈。
  • 日志输出:通过 console.log 输出关键信息,可以快速定位问题。
实践:部署到GitHub Pages

部署到GitHub Pages的步骤

  1. 打包项目

    npm run build
  2. 创建 gh-pages 分支

    git checkout -b gh-pages
  3. 安装 gh-pages

    npm install gh-pages --save-dev
  4. 配置 package.json

    package.json 中添加以下脚本:

    "scripts": {
     "deploy": "gh-pages -d build"
    }
  5. 部署项目

    npm run deploy

这会将 build 目录的内容推送到 gh-pages 分支,并自动部署到 GitHub Pages。

验证部署结果

部署完成后,可以在 GitHub Pages 中查看部署结果。访问项目仓库的 GitHub Pages 页面,确保项目可以正常运行。

https://username.github.io/repo-name/

通过这些步骤,可以将 React+TypeScript 项目成功部署到 GitHub Pages。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP