React入门教程

207 阅读16分钟

React入门教程

React是一个用于构建用户界面的JavaScript库,它可以让你用组件的方式来开发复杂的Web应用。本文将介绍React的基本概念和用法,帮助你快速入门React开发。

什么是React

React是由Facebook开发并开源的一个JavaScript库,它的核心思想是使用组件来构建用户界面。组件是一种封装了状态和行为的可复用的代码单元,它可以接收一些输入(称为props)并输出一些界面元素(称为JSX)。React会根据组件的状态和输入自动更新界面,让你不用关心DOM操作和数据同步的细节。

React有以下几个特点:

  • 声明式:你只需要描述你想要的界面是什么样子,而不需要手动操作DOM来实现。
  • 组件化:你可以将界面拆分成多个独立的组件,每个组件都有自己的状态和逻辑,可以复用和组合。
  • 单向数据流:你可以将数据从父组件传递给子组件,但不能反过来,这样可以保证数据的一致性和可预测性。
  • 跨平台:你可以使用React来开发Web、移动端、桌面端等不同平台的应用,只需要少量的平台相关代码。

如何使用React

要使用React,你需要先安装Node.js和npm(Node.js的包管理器),然后在命令行中执行以下命令:

# 创建一个名为my-app的React项目
npx create-react-app my-app

# 进入项目目录
cd my-app

# 启动开发服务器
npm start

这样就会在浏览器中打开一个默认的React应用,你可以在src目录中修改代码并查看效果。

一个最简单的React应用如下:

// 引入React库
import React from 'react';
// 引入ReactDOM库,用于将React渲染到DOM中
import ReactDOM from 'react-dom';

// 定义一个名为Hello的组件,它接收一个name属性,并返回一个<h1>元素
function Hello(props) {
  return <h1>Hello, {props.name}</h1>;
}

// 将Hello组件渲染到id为root的DOM元素中,并传入name属性为World
ReactDOM.render(
  <Hello name="World" />,
  document.getElementById('root')
);

这段代码中,我们使用了以下几个概念:

  • JSX:一种类似于HTML的语法,用于描述界面元素。它可以嵌入JavaScript表达式,用花括号包裹。例如,<h1>Hello, {props.name}</h1>就是一个JSX元素,它会根据props.name的值动态生成一个h1元素。
  • 组件:一种封装了状态和行为的可复用的代码单元,它可以是一个函数或者一个类。例如,function Hello(props) {...}就是一个函数组件,它接收一个props对象作为参数,并返回一个JSX元素。
  • props:一种从父组件向子组件传递数据的方式,它是一个只读的对象。例如,<Hello name="World" />就是向Hello组件传递了一个name属性,它可以在Hello组件中通过props.name来访问。
  • ReactDOM.render:一种将React组件渲染到DOM中的方法,它接收两个参数:一个React元素和一个DOM元素。例如,ReactDOM.render(<Hello name="World" />, document.getElementById('root'))就是将Hello组件渲染到id为root的DOM元素中。

如何管理状态

React是一个用于构建用户界面的库,它提供了一种声明式的方式来定义组件和它们之间的交互。组件是React应用的基本单元,它们可以接收一些输入(称为props)并返回一些输出(称为JSX)。组件也可以拥有自己的内部状态(称为state),用来存储一些与组件相关的数据,比如用户输入、计时器、表单等。

状态是组件的一个重要概念,它决定了组件的渲染结果和行为。状态是可变的,也就是说,它可以在组件的生命周期中发生改变。当状态发生改变时,React会自动重新渲染组件,以反映最新的状态。

管理状态的方法有很多种,但是最常见和推荐的有两种:使用类组件的setState方法和使用函数组件的useState钩子。

使用类组件的setState方法

类组件是一种定义组件的方式,它使用ES6的class语法来创建一个继承自React.Component的类。类组件可以在其构造函数中初始化一个state对象,用来存储组件的初始状态。然后,类组件可以在其任何方法中使用this.setState方法来更新状态。this.setState方法接收一个对象或一个函数作为参数,它会将参数中的属性合并到当前的state中,并触发组件的重新渲染。例如:

import React, { Component } from 'react';

class Counter extends Component {
  constructor(props) {
    super(props);
    // 初始化state
    this.state = {
      count: 0
    };
  }

  // 定义一个增加计数的方法
  increment = () => {
    // 使用setState方法更新状态
    this.setState({
      count: this.state.count + 1
    });
  };

  // 定义一个渲染方法
  render() {
    // 从state中解构出count
    const { count } = this.state;
    return (
      <div>
        <p>当前计数:{count}</p>
        <button onClick={this.increment}>点击增加</button>
      </div>
    );
  }
}

export default Counter;

使用函数组件的useState钩子

函数组件是另一种定义组件的方式,它使用一个普通的JavaScript函数来返回JSX。函数组件没有自己的state,也没有生命周期方法,因此它们被认为是无状态的或纯粹的。然而,在React 16.8版本中,引入了一种新特性,称为钩子(hooks),它允许函数组件使用一些React提供的特性,比如状态、副作用、上下文等。

useState是React提供的一个基本钩子,它可以让函数组件拥有自己的状态。useState接收一个参数作为初始状态,并返回一个数组,包含两个元素:当前状态和更新状态的函数。我们可以使用数组解构语法来获取这两个元素,并给它们命名。然后,我们可以在函数组件中使用这两个元素来读取和修改状态,并触发组件的重新渲染。例如:

import React, { useState } from 'react';

function Counter() {
  // 使用useState钩子创建一个状态和更新状态的函数
  const [count, setCount] = useState(0);

  // 定义一个增加计数的函数
  const increment = () => {
    // 使用更新状态的函数修改状态
    setCount(count + 1);
  };

  // 返回JSX
  return (
    <div>
      <p>当前计数:{count}</p>
      <button onClick={increment}>点击增加</button>
    </div>
  );
}

export default Counter;

如何使用Redux管理状态

Redux是一个用于管理应用状态的库,它可以与React配合使用,实现一个可预测、可调试、可扩展的状态管理方案。Redux的核心思想是将应用的状态存储在一个单一的对象中,称为store,然后通过一些规则来控制状态的更新和访问。

Redux的基本原则有三个:

  • 单一数据源:应用的状态只存储在一个store中,这样可以方便地监控和调试状态的变化。
  • 状态不可变:应用的状态不能直接被修改,而是通过派发(dispatch)一些描述行为的对象,称为action,来触发状态的更新。这样可以保证状态的一致性和可追溯性。
  • 纯函数更新:状态的更新逻辑由一些纯函数来完成,称为reducer,它们接收当前的状态和一个action,并返回一个新的状态。这样可以保证状态的可预测性和可测试性。

要使用Redux管理React应用的状态,我们需要做以下几个步骤:

  • 定义action类型:action类型是一个字符串常量,用来标识不同的action,比如INCREMENTDECREMENT等。
  • 定义action创建函数:action创建函数是一个简单的函数,用来返回一个action对象,比如increment()decrement()等。
  • 定义reducer函数:reducer函数是一个纯函数,用来根据当前的状态和一个action,返回一个新的状态。通常我们会使用switch语句来根据不同的action类型来执行不同的逻辑。
  • 创建store对象:store对象是Redux提供的一个核心对象,它负责存储应用的状态、派发action、注册监听器等。我们可以使用Redux提供的createStore函数来创建一个store对象,并传入一个reducer函数作为参数。
  • 连接React组件:我们可以使用React Redux提供的Provider组件和connect函数来将React组件和Redux store连接起来。Provider组件可以让所有的子组件都能访问到store对象,而connect函数可以让我们定义一些映射函数,将store中的状态和派发action的方法注入到组件的props中。

下面是一个简单的例子,演示了如何使用Redux管理一个计数器应用的状态:

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider, connect } from 'react-redux';

// 定义action类型
const INCREMENT = 'INCREMENT';
const DECREMENT = 'DECREMENT';

// 定义action创建函数
const increment = () => ({ type: INCREMENT });
const decrement = () => ({ type: DECREMENT });

// 定义reducer函数
const counterReducer = (state = 0, action) => {
  switch (action.type) {
    case INCREMENT:
      return state + 1;
    case DECREMENT:
      return state - 1;
    default:
      return state;
  }
};

// 创建store对象
const store = createStore(counterReducer);

// 定义Counter组件
function Counter(props) {
  // 从props中解构出count、increment和decrement
  const { count, increment, decrement } = props;
  return (
    <div>
      <p>当前计数:{count}</p>
      <button onClick={increment}>点击增加</button>
      <button onClick={decrement}>点击减少</button>
    </div>
  );
}

// 定义映射state到props的函数
const mapStateToProps = (state) => ({
  count: state
});

// 定义映射dispatch到props的函数
const mapDispatchToProps = (dispatch) => ({
  increment: () => dispatch(increment()),
  decrement: () => dispatch(decrement())
});

// 使用connect函数连接Counter组件和store对象
const ConnectedCounter = connect(mapStateToProps, mapDispatchToProps)(Counter);

// 使用Provider组件包裹根组件,并传入store对象作为属性
ReactDOM.render(
  <Provider store={store}>
    <ConnectedCounter />
  </Provider>,
  document.getElementById('root')
);

如何使用React Router实现路由

路由是一种在应用中根据不同的URL显示不同的页面或组件的方式,它可以让我们的应用更加动态和交互性。React本身并不提供路由的功能,但是我们可以使用一个第三方库,叫做React Router,来实现路由。

React Router是一个用于管理React应用的路由的库,它提供了一些组件和钩子,让我们可以方便地定义和切换路由。React Router有多个版本,适用于不同的平台,比如web、native、static等。这里我们主要介绍web版本,也就是react-router-dom库。

要使用React Router实现路由,我们需要做以下几个步骤:

  • 安装react-router-dom库:我们可以使用npm或yarn来安装react-router-dom库,比如npm install react-router-domyarn add react-router-dom
  • 创建BrowserRouter对象:BrowserRouter对象是React Router提供的一个核心对象,它负责监听浏览器的URL变化,并将其同步到应用的状态中。我们可以使用React Router提供的createBrowserRouter函数来创建一个BrowserRouter对象,并传入一个数组作为参数,表示我们定义的路由规则。每个路由规则是一个对象,包含两个属性:path和element。path表示匹配的URL路径,element表示渲染的组件或元素。
  • 使用RouterProvider组件:RouterProvider组件是React Router提供的一个高阶组件,它可以让所有的子组件都能访问到BrowserRouter对象。我们需要将RouterProvider组件包裹在我们的根组件上,并传入BrowserRouter对象作为属性。
  • 使用Link组件和useNavigate钩子:Link组件和useNavigate钩子是React Router提供的两种方式,让我们可以在应用中切换路由。Link组件是一个类似于<a>标签的组件,它可以接收一个to属性作为目标URL,并保留浏览器的历史记录。useNavigate钩子是一个函数,它可以返回一个navigate函数,让我们可以在代码中动态地跳转到指定的URL,并接收一些选项,比如是否替换当前历史记录、是否保留状态等。

下面是一个简单的例子,演示了如何使用React Router实现路由:

import React from 'react';
import ReactDOM from 'react-dom';
import { createBrowserRouter, RouterProvider, Link, useNavigate } from 'react-router-dom';

// 定义一些页面或组件
const Home = () => <div>Home</div>;
const About = () => <div>About</div>;
const Contact = () => <div>Contact</div>;
const NotFound = () => <div>Not Found</div>;

// 创建一个BrowserRouter对象,并传入一个数组作为参数,表示路由规则
const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  { path: '/about', element: <About /> },
  { path: '/contact', element: <Contact /> },
  { path: '*', element: <NotFound /> },
]);

// 定义一个App组件
function App() {
  // 使用useNavigate钩子获取一个navigate函数
  const navigate = useNavigate();
  return (
    // 使用RouterProvider组件包裹根组件,并传入router对象作为属性
    <RouterProvider router={router}>
      <div>
        <h1>React Router Example</h1>
        // 使用Link组件创建一些导航链接
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/contact">Contact</Link>
          </li>
        </ul>
        // 使用navigate函数在代码中跳转路由
        <button onClick={() => navigate('/about')}>Go to About</button>
      </div>
    </RouterProvider>
  );
}

// 渲染App组件到页面上
ReactDOM.render(<App />, document.getElementById('root'));

如何使用嵌套路由

嵌套路由是一种在应用中根据不同的URL显示不同的页面或组件的方式,它可以让我们的应用更加动态和交互性。嵌套路由的特点是,父路由可以控制子路由的渲染,也就是说,当我们访问一个嵌套路由时,父路由和子路由都会被渲染出来。这样可以实现一些复杂的布局和导航,比如论坛、博客等。

要使用React Router实现嵌套路由,我们需要遵循以下几个步骤:

  • 定义父路由和子路由:我们可以使用React Router提供的createBrowserRouter函数来创建一个BrowserRouter对象,并传入一个数组作为参数,表示我们定义的路由规则。每个路由规则是一个对象,包含两个属性:path和element。path表示匹配的URL路径,element表示渲染的组件或元素。如果我们想要定义一个嵌套路由,我们可以在父路由的element中再嵌套一个数组,表示子路由规则。例如:
const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  {
    path: '/user',
    element: <User />,
    children: [
      { path: '/', element: <Profile /> },
      { path: 'account', element: <Account /> },
    ],
  },
  { path: '*', element: <NotFound /> },
]);

这里我们定义了一个/user的父路由,它渲染了User组件,并且有两个子路由:/user/和/user/account,分别渲染了Profile和Account组件。

  • 使用RouterProvider组件:RouterProvider组件是React Router提供的一个高阶组件,它可以让所有的子组件都能访问到BrowserRouter对象。我们需要将RouterProvider组件包裹在我们的根组件上,并传入BrowserRouter对象作为属性。
  • 使用Link组件和useNavigate钩子:Link组件和useNavigate钩子是React Router提供的两种方式,让我们可以在应用中切换路由。Link组件是一个类似于<a>标签的组件,它可以接收一个to属性作为目标URL,并保留浏览器的历史记录。useNavigate钩子是一个函数,它可以返回一个navigate函数,让我们可以在代码中动态地跳转到指定的URL,并接收一些选项,比如是否替换当前历史记录、是否保留状态等。
  • 使用Outlet组件:Outlet组件是React Router提供的一个特殊的组件,它可以渲染当前匹配的子路由。我们需要在父路由对应的组件中使用Outlet组件来占位,这样当我们访问子路由时,Outlet组件就会被替换为子路由对应的组件。

下面是一个完整的例子,演示了如何使用React Router实现嵌套路由:

import React from 'react';
import ReactDOM from 'react-dom';
import { createBrowserRouter, RouterProvider, Link, useNavigate, Outlet } from 'react-router-dom';

// 定义一些页面或组件
const Home = () => <div>Home</div>;
const User = () => (
  <div>
    <h1>User</h1>
    <nav>
      <Link to="/">Profile</Link>
      <Link to="account">Account</Link>
    </nav>
    // 使用Outlet组件来渲染子路由
    <Outlet />
  </div>
);
const Profile = () => <div>Profile</div>;
const Account = () => <div>Account</div>;
const NotFound = () => <div>Not Found</div>;

// 创建一个BrowserRouter对象,并传入一个数组作为参数,表示路由规则
const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  {
    path: '/user',
    element: <User />,
    children: [
      { path: '/', element: <Profile /> },
      { path: 'account', element: <Account /> },
    ],
  },
  { path: '*', element: <NotFound /> },
]);

// 定义一个App组件
function App() {
  // 使用useNavigate钩子获取一个navigate函数
  const navigate = useNavigate();
  return (
    // 使用RouterProvider组件包裹根组件,并传入router对象作为属性
    <RouterProvider router={router}>
      <div>
        <h1>React Router Example</h1>
        // 使用Link组件创建一些导航链接
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/user">User</Link>
          </li>
        </ul>
        // 使用navigate函数在代码中跳转路由
        <button onClick={() => navigate('/user/account')}>Go to Account</button>
      </div>
    </RouterProvider>
  );
}

// 渲染App组件到页面上
ReactDOM.render(<App />, document.getElementById('root'));

如何使用路由参数

路由参数是一种在URL中动态设置和获取值的方式,它可以让我们根据不同的参数来渲染不同的组件或数据。比如,我们想要实现一个博客应用,当我们访问/blog/:id时,就可以显示对应id的博客文章。

要使用React Router实现路由参数,我们需要遵循以下几个步骤:

  • 定义路由参数:我们可以在路由规则的path属性中使用冒号(:)来标识一个参数,比如path: '/blog/:id'。这样,当我们访问/blog/123时,就会匹配到这个路由,并且把123作为id参数的值。
  • 使用useParams钩子:useParams钩子是React Router提供的一个函数,它可以返回一个对象,包含了当前URL中的所有参数的键值对。我们可以在路由对应的组件中使用useParams钩子,并解构出我们需要的参数。例如:
import React from 'react';
import { createBrowserRouter, RouterProvider, Link, useParams } from 'react-router-dom';

// 定义一些页面或组件
const Home = () => <div>Home</div>;
const Blog = () => {
  // 使用useParams钩子,并解构出id参数
  const { id } = useParams();
  return <div>Blog {id}</div>;
};
const NotFound = () => <div>Not Found</div>;

// 创建一个BrowserRouter对象,并传入一个数组作为参数,表示路由规则
const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  // 定义一个路由参数:id
  { path: '/blog/:id', element: <Blog /> },
  { path: '*', element: <NotFound /> },
]);

// 定义一个App组件
function App() {
  return (
    // 使用RouterProvider组件包裹根组件,并传入router对象作为属性
    <RouterProvider router={router}>
      <div>
        <h1>React Router Example</h1>
        // 使用Link组件创建一些导航链接
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/blog/1">Blog 1</Link>
          </li>
          <li>
            <Link to="/blog/2">Blog 2</Link>
          </li>
        </ul>
      </div>
    </RouterProvider>
  );
}

// 渲染App组件到页面上
ReactDOM.render(<App />, document.getElementById('root'));

如何使用多个路由参数

有时候,我们可能需要在URL中传递多个参数,比如/blog/:category/:id,表示博客的分类和文章的id。要使用React Router实现多个路由参数,我们需要遵循以下几个步骤:

  • 定义多个路由参数:我们可以在路由规则的path属性中使用冒号(:)来标识多个参数,比如path: '/blog/:category/:id'。这样,当我们访问/blog/react/123时,就会匹配到这个路由,并且把react作为category参数的值,把123作为id参数的值。
  • 使用useParams钩子:useParams钩子是React Router提供的一个函数,它可以返回一个对象,包含了当前URL中的所有参数的键值对。我们可以在路由对应的组件中使用useParams钩子,并解构出我们需要的参数。例如:
import React from 'react';
import { createBrowserRouter, RouterProvider, Link, useParams } from 'react-router-dom';

// 定义一些页面或组件
const Home = () => <div>Home</div>;
const Blog = () => {
  // 使用useParams钩子,并解构出category和id参数
  const { category, id } = useParams();
  return <div>Blog {category} {id}</div>;
};
const NotFound = () => <div>Not Found</div>;

// 创建一个BrowserRouter对象,并传入一个数组作为参数,表示路由规则
const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  // 定义两个路由参数:category和:id
  { path: '/blog/:category/:id', element: <Blog /> },
  { path: '*', element: <NotFound /> },
]);

// 定义一个App组件
function App() {
  return (
    // 使用RouterProvider组件包裹根组件,并传入router对象作为属性
    <RouterProvider router={router}>
      <div>
        <h1>React Router Example</h1>
        // 使用Link组件创建一些导航链接
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/blog/react/1">Blog React 1</Link>
          </li>
          <li>
            <Link to="/blog/vue/2">Blog Vue 2</Link>
          </li>
        </ul>
      </div>
    </RouterProvider>
  );
}

// 渲染App组件到页面上
ReactDOM.render(<App />, document.getElementById('root'));

后续继续补充...