手记

React18项目实战:从零开始搭建你的第一个React应用

概述

本文将详细介绍如何使用React18从零开始搭建你的第一个React应用,包括环境搭建、组件创建、状态管理以及项目实战等内容。通过本文,你将学会如何使用最新的React18特性进行项目开发,并掌握基本的项目部署方法。文中还将介绍一些常用的库和工具,如React Router和Redux,帮助你更好地构建应用。

React18简介与环境搭建

React18新特性简介

React18是一个重要的版本更新,它引入了许多重要的改进与新特性,例如自动批量更新、时间切片等等。其中,自动批量更新允许React在用户交互或事件期间将多个状态更新批量处理,这提高了性能并减少了不必要的重绘。时间切片(Concurrent Mode)则为开发人员提供了更细粒度的控制,使得应用可以更高效地响应用户输入,避免了卡顿。

开发环境搭建

在开始使用React18开发应用之前,首先需要搭建好开发环境。开发环境需要安装以下几个工具:

  1. Node.js:首先确保你的电脑上已经安装了Node.js。可以通过访问官方网站(https://nodejs.org/)获取安装包
  2. npm/yarn:npm是Node.js的默认包管理工具,而yarn是一个更快速、更可靠的包管理器。安装Node.js时会附带npm,但你可以选择安装yarn来替代npm。可以在终端中运行npm install -g yarn来安装yarn。
  3. create-react-app:使用npx create-react-app my-app创建一个新的React项目,其中my-app是你项目的名称。

安装完成后可以通过运行npx create-react-app my-app来创建你的第一个React项目。这将生成一个基本的React应用结构。以下是如何创建一个React项目的一系列命令:

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

安装完成后,你将看到一些必要的文件和文件夹,如src文件夹。在src文件夹中,你可以找到一些重要的文件和文件夹:

  • App.js:这是应用的主组件。
  • index.js:这是应用的入口文件。
  • App.css:这是App.js的CSS样式文件。
  • index.css:这是整个应用的全局样式文件。

为了展示如何创建一个基本的React应用,我们可以在App.js文件中编写一些简单的代码:

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

function App() {
  return (
    <div className="App">
      <h1>Hello, World!</h1>
    </div>
  );
}

export default App;

这段代码定义了一个名为App的函数组件,它返回一个包含一个h1标签的div元素。这个div元素还应用了一个名为App的CSS类。export default App;这行代码将App组件导出,以便在其他文件中使用。

index.js文件中,可以看到App组件被渲染到root元素中:

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')
);

index.js文件中导入了React和ReactDOM,然后将App组件渲染到root元素中。React.StrictMode用于在生产环境中提高应用的健壮性,测试潜在的问题并提供警告。

创建和运行应用后,你可以访问localhost:3000来查看应用的运行情况。此时,你应该能够看到一个显示“Hello, World!”的页面。

基本组件与JSX语法

组件的基本概念与创建方法

在React中,组件是构建用户界面的原子单元。组件可以被视作带有特定功能的小型独立的模块,这些功能可以包括渲染界面、处理用户输入、响应状态变化等。组件的创建有两种方法:

  1. 函数组件:使用函数定义的组件,通常用于简单的渲染逻辑。例如:

    function Welcome(props) {
     return <h1>Hello, {props.name}</h1>;
    }
  2. 类组件:使用React.Component继承定义的组件,通常用于更复杂的状态管理。例如:

    import React from 'react';
    
    class Welcome extends React.Component {
     render() {
       return <h1>Hello, {this.props.name}</h1>;
     }
    }

JSX语法入门与使用技巧

JSX是一种在JavaScript中使用的语法扩展,它允许你编写类似于HTML的代码。JSX代码会被编译成标准的JavaScript。以下是一些JSX的基本语法:

  • 元素与标签:JSX中的标签可以是HTML标签,也可以是自定义组件。例如:

    <div>
    Hello, world!
    </div>
  • 属性:JSX中的属性可以接受JavaScript表达式。例如:

    <div className="container">
    Hello, {name}
    </div>
  • JSX表达式的嵌入:可以在JSX中嵌入JavaScript表达式,只需在花括号中写JavaScript代码即可。例如:

    <div>
    The date is {new Date().toLocaleDateString()}
    </div>
  • JSX数组:可以使用数组来渲染列表。例如:

    const items = ['item1', 'item2', 'item3'];
    const listItems = items.map((item) => <li>{item}</li>);
    return <ul>{listItems}</ul>;
  • JSX条件渲染:可以根据条件渲染不同的元素。例如:

    const isLoggedIn = true;
    let element;
    if (isLoggedIn) {
    element = <div>You are logged in!</div>;
    } else {
    element = <div>You are not logged in.</div>;
    }

属性传递与组件通信

组件可以通过属性(props)来通信。父组件可以向子组件传递属性,子组件可以使用这些属性来定制自己的行为。例如,父组件可以向子组件传递一个name属性,如:

const Welcome = (props) => {
  return <h1>Hello, {props.name}</h1>;
};

function App() {
  return <Welcome name="Jane" />;
}

子组件可以通过函数属性来与父组件通信。例如,父组件可以向子组件传递一个回调函数作为属性,子组件可以在适当的时候调用这个回调函数:

const Button = (props) => {
  return <button onClick={props.onClick}>Click me</button>;
};

function App() {
  const handleClick = () => {
    console.log('Button clicked!');
  };

  return <Button onClick={handleClick} />;
}

通过这种方式,父组件可以监听子组件的事件并做出响应。

状态(State)与生命周期

状态管理方法与最佳实践

状态(state)是React组件中的一种数据存储方式,它允许组件根据数据的变化来渲染不同的内容。状态可以在函数组件中使用useState Hook来管理,也可以在类组件中通过this.state来管理。

  1. 使用useState Hook:在函数组件中,可以使用useState Hook来管理状态。useState返回一个数组,数组的第一个元素是当前的状态值,第二个元素是更新状态值的函数。例如:

    import React, { useState } from 'react';
    
    function Counter() {
     const [count, setCount] = useState(0);
    
     return (
       <div>
         <p>Count: {count}</p>
         <button onClick={() => setCount(count + 1)}>Increment</button>
       </div>
     );
    }
  2. 使用this.setState:在类组件中,可以使用setState方法来更新状态。setState是一个异步方法,它可以接受一个对象来更新状态,也可以接受一个函数来计算下一个状态。例如:

    import React, { Component } from 'react';
    
    class Counter extends Component {
     constructor(props) {
       super(props);
       this.state = { count: 0 };
     }
    
     increment = () => {
       this.setState((prevState) => {
         return { count: prevState.count + 1 };
       });
     };
    
     render() {
       return (
         <div>
           <p>Count: {this.state.count}</p>
           <button onClick={this.increment}>Increment</button>
         </div>
       );
     }
    }

组件生命周期基本概念

在React中,组件的生命周期分为三个主要阶段:挂载(Mounting)、更新(Updating)和卸载(Unmounting)。每个阶段都有相应的生命周期方法,这些方法在组件的不同阶段会被自动调用。

  1. 挂载阶段:组件首次渲染到DOM中的过程。

    • constructor(props):在组件实例化时调用,通常在这里初始化状态。
    • static getDerivedStateFromProps(props, state):在组件被渲染之前,React会在调用render方法之前调用该方法。这是在render方法被调用之前修改状态的最后机会。
    • render():返回要渲染的元素。
    • componentDidMount():在组件挂载后立即调用。可以在这个方法中执行数据获取、DOM操作等初始化操作。
    • getDerivedStateFromProps:在挂载前后调用,允许根据新的属性值修改状态。
  2. 更新阶段:组件状态或属性发生变化时,重新渲染的过程。

    • static getDerivedStateFromProps(props, state):在组件更新时再次调用,允许你根据新的属性值更新组件的状态。
    • shouldComponentUpdate(nextProps, nextState):在组件更新之前调用,返回一个布尔值,表示组件是否需要更新。
    • getSnapshotBeforeUpdate(prevProps, prevState):在DOM更新前调用,返回值会传递给componentDidUpdate
    • render():更新DOM时重新调用。
    • componentDidUpdate(prevProps, prevState, snapshot):在DOM更新后调用。
  3. 卸载阶段:组件从DOM中移除的过程。
    • componentWillUnmount():在组件卸载和DOM元素从DOM中移除之前调用。可以在这个方法中清理定时器、取消网络请求等资源。

常见生命周期方法介绍

以下是一些常见的生命周期方法及其用途:

  • componentDidMount():在组件挂载后立即调用,可以在这里执行数据获取、DOM操作等初始化操作。
  • componentDidUpdate(prevProps, prevState):在组件更新后调用,可以在这里执行一些副作用操作,如DOM操作、API请求等。
  • componentWillUnmount():在组件卸载和DOM元素从DOM中移除之前调用,可以在这里执行一些清理操作,如取消定时器、注销事件监听器等。
import React, { Component } from 'react';

class LifecycleExample extends Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    console.log('Component did mount');
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.count !== this.state.count) {
      console.log('Component did update');
    }
  }

  componentWillUnmount() {
    console.log('Component will unmount');
  }

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

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
      </div>
    );
  }
}
常见库与工具介绍

路由管理器(如React Router)

React Router是React中用于处理页面路由和导航的库。它允许你定义路由,根据不同的URL显示不同的组件。

  1. 安装React Router

    npm install react-router-dom
  2. 基本使用

    import React from 'react';
    import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
    
    function App() {
     return (
       <Router>
         <Switch>
           <Route path="/" exact component={Home} />
           <Route path="/about" component={About} />
           <Route path="/users" component={Users} />
         </Switch>
       </Router>
     );
    }
    
    function Home() {
     return <h2>Home</h2>;
    }
    
    function About() {
     return <h2>About</h2>;
    }
    
    function Users() {
     return <h2>Users</h2>;
    }
    
    export default App;

    这个示例定义了三个路由,分别对应于不同的路径和组件。Switch组件用于确定当前路径匹配哪个路由。

状态管理库(如Redux)

Redux是一个用于管理复杂状态的库,它可以让你的状态管理更加集中和可预测。以下是使用Redux的基本步骤:

  1. 安装Redux

    npm install redux
  2. 定义Store

    import { createStore } from 'redux';
    
    function counterReducer(state = 0, action) {
     switch (action.type) {
       case 'INCREMENT':
         return state + 1;
       case 'DECREMENT':
         return state - 1;
       default:
         return state;
     }
    }
    
    const store = createStore(counterReducer);
  3. 定义Action Creator

    const increment = () => ({ type: 'INCREMENT' });
    const decrement = () => ({ type: 'DECREMENT' });
  4. 连接组件与Redux

    import React from 'react';
    import { connect } from 'react-redux';
    
    const Counter = ({ count, increment, decrement }) => (
     <div>
       <p>Count: {count}</p>
       <button onClick={increment}>Increment</button>
       <button onClick={decrement}>Decrement</button>
     </div>
    );
    
    const mapStateToProps = (state) => ({
     count: state
    });
    
    const mapDispatchToProps = (dispatch) => ({
     increment: () => dispatch(increment()),
     decrement: () => dispatch(decrement())
    });
    
    export default connect(mapStateToProps, mapDispatchToProps)(Counter);

UI库与框架(如Ant Design)

Ant Design是一个高质量的React组件库,它提供了丰富的UI组件和设计规范,使开发过程更加高效。以下是使用Ant Design的基本步骤:

  1. 安装Ant Design

    npm install antd
  2. 使用组件

    import React from 'react';
    import { Button, Input } from 'antd';
    
    const App = () => (
     <div>
       <Input placeholder="input placeholder" />
       <Button type="primary">Primary Button</Button>
     </div>
    );
    
    export default App;

在上述示例中,InputButton组件来自Ant Design库,通过简单的导入和使用,可以快速构建出美观且功能完整的界面。

项目实战:构建一个简易博客

需求分析与项目规划

在本节中,我们将使用React18和相关库构建一个简易博客应用。该博客应用将具备以下功能:

  • 用户登录:用户可以登录到应用以查看个人博客。
  • 博客列表:显示当前用户发布的所有博客文章。
  • 博客详情:点击博客文章可以查看详细内容。
  • 博客编辑功能:用户可以编辑或删除自己的博客文章。

页面布局与组件划分

为了使应用结构清晰,我们需要对页面进行合理的布局并将页面划分为多个组件。以下是应用的页面结构:

  1. 登录页面(Login):提供登录表单,用户输入用户名和密码。
  2. 博客列表页面(BlogList):显示当前用户发布的所有博客文章。
  3. 博客详情页面(BlogDetail):显示博客文章的详细内容。
  4. 博客编辑页面(BlogEdit):允许用户编辑或删除自己的博客文章。

功能实现与调试

我们将从实现登录页面开始,然后实现博客列表、详情和编辑页面。

实现登录页面

登录页面包含一个表单,用户可以通过输入用户名和密码进行登录。为了实现这个功能,我们需要使用表单组件和状态管理。

import React, { useState } from 'react';
import { Button, Input } from 'antd';

const LoginForm = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleLogin = () => {
    console.log(`Username: ${username}, Password: ${password}`);
    // 实际应用中,这里应该进行用户验证和跳转等操作
  };

  return (
    <div>
      <Input
        type="text"
        placeholder="Username"
        onChange={(e) => setUsername(e.target.value)}
      />
      <Input
        type="password"
        placeholder="Password"
        onChange={(e) => setPassword(e.target.value)}
      />
      <Button type="primary" onClick={handleLogin}>
        Login
      </Button>
    </div>
  );
};

export default LoginForm;

实现博客列表页面

博客列表页面显示当前用户的所有博客文章。为了实现这个功能,我们需要从后端获取博客数据并渲染到页面上。

import React, { useState, useEffect } from 'react';
import { Card, List } from 'antd';
import axios from 'axios';

const BlogList = () => {
  const [blogs, setBlogs] = useState([]);

  useEffect(() => {
    axios.get('/api/blogs').then((response) => {
      setBlogs(response.data);
    });
  }, []);

  return (
    <List
      header={<div>Blog List</div>}
      bordered
      dataSource={blogs}
      renderItem={(item) => (
        <List.Item>
          <Card title={item.title} description={item.content} />
        </List.Item>
      )}
    />
  );
};

export default BlogList;

实现博客详情页面

博客详情页面显示博客文章的详细内容,包括标题、内容、作者等信息。

import React from 'react';

const BlogDetail = ({ blog }) => {
  return (
    <div>
      <h1>{blog.title}</h1>
      <p>{blog.content}</p>
      <p>Author: {blog.author}</p>
    </div>
  );
};

export default BlogDetail;

实现博客编辑页面

博客编辑页面允许用户编辑或删除自己的博客文章。为了实现这个功能,我们需要提供表单来编辑博客内容,并提供删除按钮。

import React, { useState } from 'react';
import { Input, Button } from 'antd';

const BlogEdit = ({ blog, updateBlog, deleteBlog }) => {
  const [title, setTitle] = useState(blog.title);
  const [content, setContent] = useState(blog.content);

  const handleUpdate = () => {
    updateBlog({ ...blog, title, content });
  };

  const handleDelete = () => {
    deleteBlog(blog.id);
  };

  return (
    <div>
      <Input
        type="text"
        placeholder="Title"
        value={title}
        onChange={(e) => setTitle(e.target.value)}
      />
      <Input.TextArea
        placeholder="Content"
        value={content}
        onChange={(e) => setContent(e.target.value)}
      />
      <Button type="primary" onClick={handleUpdate}>
        Update
      </Button>
      <Button type="danger" onClick={handleDelete}>
        Delete
      </Button>
    </div>
  );
};

export default BlogEdit;
项目部署与上线

构建与优化项目

在部署之前,需要先构建项目。可以通过以下命令来构建项目:

npm run build

npm run build命令会编译和优化应用代码,并将结果输出到build目录。构建后的文件已经被优化,可以直接部署到任何静态文件服务器上。

$ npm run build

> my-app@0.1.0 build
> react-scripts build

 Creating an optimized production build...
 Compiled successfully.

 File sizes after gzip:

 build 3.12 kB
 build/static/js/2.941d9038.chunk.js 557 B
 build/static/js/main.8033886a.chunk.js 557 B
 build/static/css/main.e9723520.chunk.css 557 B

 Your build is minified and optimized for production.
 You can now serve it from a CDN.

构建完成后,你会在项目目录下看到一个build文件夹,里面包含所有构建后的静态文件。这些文件可以被部署到任何可以托管静态文件的服务器上。

部署到GitHub Pages或其他服务器

部署到GitHub Pages:

  1. 创建GitHub仓库:请先创建一个GitHub仓库,例如my-app
  2. 配置package.json:在package.json中添加homepage字段,例如:

    "homepage": "https://username.github.io/my-app",
  3. 设置GitHub Actions:配置GitHub Actions以自动构建和部署到GitHub Pages。可以在.github/workflows目录下创建一个main.yml文件,内容如下:

    name: Deploy to GitHub Pages
    on:
     push:
       branches:
         - main
    jobs:
     build-and-deploy:
       runs-on: ubuntu-latest
       steps:
         - uses: actions/checkout@v2
           with:
             fetch-depth: 1
         - name: Set up Node.js
           uses: actions/setup-node@v2
           with:
             node-version: '14.x'
         - name: Install dependencies
           run: npm ci
         - name: Build
           run: npm run build
         - name: Deploy
           uses: peaceiris/actions-gh-pages@v3
           with:
             build-dir: ./build
             github-token: ${{ secrets.GITHUB_TOKEN }}
  4. 推送代码:将代码推送到GitHub仓库。

部署到其他静态文件服务器(例如Netlify、Vercel):

  1. 注册并创建项目:在Netlify、Vercel等平台上注册并创建新的项目。
  2. 连接仓库:将项目与GitHub仓库连接起来。
  3. 构建和部署:选择构建命令(例如npm run build)和部署目录(例如build),然后点击部署。

常见问题解决方法

  • Build Fails:如果构建失败,请检查package.json中的scripts字段是否正确配置,并确保所有依赖项都已安装。
  • Deploy Fails:如果部署失败,请检查部署配置(例如GitHub Actions工作流程文件或Netlify环境变量)是否正确配置。
  • 404 Not Found:如果页面加载显示404错误,请确保部署目录和路径配置正确,并且构建输出文件存在并被正确托管。
0人推荐
随时随地看视频
慕课网APP