前端开发必学:React 基础入门详解 – wiki基地


前端开发必学:React 基础入门详解

随着前端技术的飞速发展,各种框架和库层出不穷。而在众多前端库中,React 凭借其高效、灵活和声明式的编程范式,迅速崛起并成为了前端界的主流技术之一。无论你是刚入行的新手,还是希望转型升级的传统前端开发者,学习 React 都将是提升你技术栈、拓宽职业道路的重要一步。

本文旨在为前端初学者提供一个全面、详细的 React 基础入门指南。我们将从 React 的核心概念讲起,一步步带你搭建开发环境,理解 JSX 语法,掌握组件、Props、State 等核心元素,并通过实例加深理解。读完本文,你应该能够基本理解 React 的工作原理,并能够着手创建简单的 React 应用。

第一章:初识 React – 为什么选择它?

在深入学习之前,我们先来了解一下 React 是什么,以及它为什么如此受欢迎。

1.1 什么是 React?

React 是一个由 Facebook(现更名为 Meta)开发的用于构建用户界面的 JavaScript 库。注意,它是一个,而不是一个完整的框架(如 Angular、Vue 的早期版本)。这意味着 React 只专注于构建视图层,开发者可以自由选择其他库来处理路由、状态管理、数据请求等任务。这种灵活性是 React 的一大优点。

1.2 React 的核心特性

  • 声明式 (Declarative): React 采用声明式范式。你只需要描述 UI 在特定状态下应该是什么样子,React 会负责高效地更新和渲染组件。与传统的命令式编程(需要一步步指示如何操作 DOM)相比,声明式让代码更易于理解和维护。
  • 组件化 (Component-Based): 构建用户界面的基本单位是组件。组件是独立、可复用的 UI 模块。你可以将复杂的 UI 拆分成多个小组件,每个组件管理自己的状态和逻辑,这极大地提高了代码的可维护性和复用性。
  • 虚拟 DOM (Virtual DOM): React 在内存中维护一个虚拟的 DOM 树。当组件状态发生变化时,React 首先更新虚拟 DOM,然后通过 Diff 算法比较新旧虚拟 DOM 树的差异,最后将最少的必要变更应用到真实的 DOM 上。这种机制显著提高了应用的性能,尤其是在频繁进行 DOM 操作的场景下。
  • 一次学习,随处编写 (Learn Once, Write Anywhere): React 不仅可以用于 Web 开发(React DOM),还可以用于构建原生移动应用(React Native)、VR 应用(React 360)等。掌握了 React 的核心原理,你可以轻松地跨平台开发。

1.3 React 解决的问题

在没有现代前端框架/库之前,前端开发者需要手动操作 DOM 来更新页面,管理复杂的用户界面状态。这导致代码难以维护、性能低下(频繁操作真实 DOM)、组件复用困难。React 通过引入组件化、声明式 UI 和虚拟 DOM 等概念,极大地简化了复杂 UI 的构建和管理过程,提高了开发效率和应用性能。

第二章:环境搭建 – 迈出第一步

学习 React 的第一步是搭建开发环境。最推荐的方式是使用官方提供的脚手架工具 Create React App (CRA),它可以帮助我们快速构建一个预配置好的 React 项目,无需手动配置繁琐的构建工具(如 Webpack、Babel)。

2.1 前置条件

在开始之前,请确保你的电脑已经安装了 Node.js 和 npm(或者 yarn/pnpm)。Node.js 包含了 npm 包管理器,我们可以通过它们来安装和管理项目依赖。

你可以通过以下命令检查 Node.js 和 npm 版本:

bash
node -v
npm -v

如果未安装,请访问 Node.js 官网下载安装包进行安装。

2.2 使用 Create React App 创建项目

打开你的终端或命令行工具,执行以下命令来创建一个新的 React 项目:

bash
npx create-react-app my-react-app

  • npx 是 npm 5.2+ 版本引入的工具,可以直接执行 node_modules 中的可执行文件,而无需全局安装。
  • create-react-app 是 React 官方的脚手架工具名称。
  • my-react-app 是你希望创建的项目文件夹名称,你可以替换成任何你喜欢的名字。

执行命令后,CRA 会自动下载所需的依赖并为你创建一个包含基础文件结构的 React 项目。这个过程可能需要一些时间,请耐心等待。

2.3 运行你的第一个 React 应用

项目创建完成后,进入项目文件夹:

bash
cd my-react-app

然后启动开发服务器:

bash
npm start

或者使用 yarn:

bash
yarn start

这会启动一个本地的开发服务器,通常在 http://localhost:3000 地址上运行。你的浏览器会自动打开这个地址,显示一个包含 React 图标的欢迎页面。

恭喜你!你已经成功运行了你的第一个 React 应用。现在,你可以使用你喜欢的代码编辑器打开 my-react-app 文件夹,开始探索项目结构和修改代码了。

2.4 项目文件结构概览

使用 CRA 创建的项目通常有以下关键文件和文件夹:

my-react-app/
├── node_modules/ # 项目依赖包
├── public/ # 公共资源文件夹
│ ├── favicon.ico # 网站图标
│ ├── index.html # 唯一的 HTML 入口文件
│ └── ...
├── src/ # 源代码文件夹 (我们主要在这里编写代码)
│ ├── App.js # 应用的根组件
│ ├── index.js # 应用的入口文件,负责将根组件渲染到 index.html 中
│ ├── index.css # 全局 CSS 样式
│ ├── App.css # App 组件的样式
│ ├── logo.svg # React logo
│ ├── reportWebVitals.js # 用于测量应用性能
│ └── setupTests.js # 测试文件配置
├── .gitignore # Git 忽略文件
├── package.json # 项目配置和依赖信息
├── README.md # 项目说明文件
└── yarn.lock 或 package-lock.json # 依赖版本锁定文件

src 文件夹是我们将花费大部分时间的地方。index.js 是应用的入口,它将根组件 App 渲染到 public/index.html 中的一个 DOM 节点(通常是一个 id 为 root<div>)。

第三章:JSX – 在 JavaScript 中编写 HTML

React 使用一种叫做 JSX 的语法扩展,它允许我们在 JavaScript 代码中书写类似 HTML 的结构。这使得组件的结构和逻辑能够紧密地结合在一起,提高了代码的可读性。

3.1 什么是 JSX?

JSX (JavaScript XML) 是一种语法糖,它并不是 HTML 也不是字符串,而是一种被 Babel 这样的编译器转换成 React 元素(JavaScript 对象)的语法。

例如,下面的 JSX 代码:

jsx
const element = <h1>Hello, React!</h1>;

会被 Babel 编译成类似下面的 JavaScript 代码:

javascript
const element = React.createElement(
'h1',
null,
'Hello, React!'
);

React.createElement() 是 React API 中创建元素的方法。它接收标签名、属性对象以及子元素作为参数。

3.2 为什么使用 JSX?

  • 直观: 它非常接近我们熟悉的 HTML 语法,使得前端开发者能快速上手。
  • 表达力强: 将标记结构和 JavaScript 逻辑放在一起,更容易理解组件的渲染结果。
  • 安全性: React 在渲染 JSX 之前会进行转义,可以有效防止跨站脚本攻击 (XSS)。

3.3 JSX 的基本规则

虽然 JSX 看起来像 HTML,但有一些重要的规则需要遵守:

  1. 必须有一个根元素: JSX 片段必须包裹在一个单独的根元素中。不能返回多个并列的顶级元素。
    “`jsx
    // 错误示例
    //

    Hello

    World

    // 正确示例 (使用 div 或其他元素包裹)

    Hello

    World

    // 正确示例 (使用 React.Fragment 或 <> 包裹,不生成额外的 DOM 元素)
    <>

    Hello

    World

    “`

  2. 嵌入 JavaScript 表达式: 你可以使用大括号 {} 在 JSX 中嵌入任何有效的 JavaScript 表达式。
    “`jsx
    const name = ‘React’;
    const element =

    Hello, {name}!

    ; // 嵌入变量

    function formatUser(user) {
    return user.firstName + ‘ ‘ + user.lastName;
    }
    const user = { firstName: ‘John’, lastName: ‘Doe’ };
    const greeting =

    Welcome, {formatUser(user)}!

    ; // 嵌入函数调用
    ``
    注意:你不能在
    {}中直接使用语句(如if` 语句),但可以使用表达式(如三元运算符)。

  3. 属性使用 camelCase: HTML 属性在 JSX 中通常使用驼峰命名法 (camelCase),因为它们会转化为 JavaScript 对象的属性。

    • class 变成 className (因为 class 是 JavaScript 的保留字)
    • for 变成 htmlFor (因为 for 是 JavaScript 的保留字)
    • 其他如 tabindex 变成 tabIndexonclick 变成 onClick 等。

    jsx
    <label htmlFor="nameInput" className="form-label">Name:</label>
    <input type="text" id="nameInput" tabIndex="1" />

  4. 行内样式使用对象: HTML 的 style 属性接收一个字符串,而 JSX 的 style 属性接收一个 JavaScript 对象。属性名使用 camelCase,属性值是字符串。
    “`jsx
    const styles = {
    color: ‘blue’,
    fontSize: ’16px’, // 注意是 camelCase
    fontWeight: ‘bold’
    };

    This text is blue and bold.

    // 也可以直接写对象

    Danger!

    ``
    注意:行内样式对象中的属性值通常是字符串(带单位如 '16px'),但有些属性(如
    opacity,zIndex,fontWeight`)可以是数字。

  5. 注释: JSX 中的注释需要写在 {} 中,使用 JavaScript 的多行注释语法 /* ... */ 或单行注释 //
    jsx
    <div>
    {/* 这是一个 JSX 注释 */}
    <p>Hello</p>
    {/*
    这是一个
    多行注释
    */}
    <p>World</p>
    </div>

理解并熟练使用 JSX 是编写 React 组件的基础。

第四章:组件 – 构建 UI 的基石

组件是 React 应用的核心概念。一个组件就像是乐高积木,你可以将它们组合起来构建复杂的用户界面。

4.1 组件的定义

在 React 中,组件是独立的、可复用的 UI 单元。从概念上讲,组件就像 JavaScript 函数,它们接收任意的输入(称为 “props”),并返回描述屏幕上应该显示什么内容的 React 元素。

React 组件主要有两种类型:

  1. 函数组件 (Function Components): 这是一个简单的 JavaScript 函数,它接收 props 对象作为参数,并返回 JSX。这是 React 官方推荐的现代组件编写方式,配合 Hooks 使用非常强大。
    jsx
    function Welcome(props) {
    return <h1>Hello, {props.name}</h1>;
    }

  2. 类组件 (Class Components): ES6 的 class 定义方式,需要继承 React.Component,并且必须包含一个 render() 方法,该方法返回 JSX。类组件在 Hook 出现之前主要用于管理状态和生命周期,现在已较少用于新代码。
    jsx
    class Welcome extends React.Component {
    render() {
    return <h1>Hello, {this.props.name}</h1>;
    }
    }

    注意: 在学习基础阶段,我们将重点放在更简洁、更常用的函数组件上。

4.2 创建并渲染组件

要使用一个组件,就像使用 HTML 标签一样在 JSX 中书写它的名字:

“`jsx
// 定义一个函数组件
function Welcome(props) {
return

Hello, {props.name}

;
}

// 在另一个组件或入口文件中使用 Welcome 组件
function App() {
return (

{/ 使用 Welcome 组件,并传递一个 name 属性 /}

{/ 组件可以复用 /}

);
}

// 在 index.js 中渲染 App 组件到 DOM
import ReactDOM from ‘react-dom/client’;
import App from ‘./App’;

const container = document.getElementById(‘root’);
const root = ReactDOM.createRoot(container);
root.render();
“`

当 React 看到 <Welcome name="Sarah" /> 这样的 JSX 时,它会调用 Welcome 函数,并将 { name: 'Sarah' } 作为 props 传递进去。函数返回的 JSX 会被渲染到页面上。

组件名称必须以大写字母开头。小写字母开头的标签名会被认为是内置的 HTML 元素(如 <div>, <span>)。

第五章:Props – 组件间的数据传递

Props 是组件属性 (properties) 的缩写。它们是父组件向子组件传递数据的方式。Props 是只读的,子组件不应该修改接收到的 props。

5.1 传递 Props

在父组件使用子组件时,通过类似 HTML 属性的方式传递数据:

“`jsx
// ParentComponent.js
import ChildComponent from ‘./ChildComponent’;

function ParentComponent() {
const greeting = “Hello from Parent!”;
const user = { name: “Alice”, age: 30 };

return (

{/ 传递字符串和对象作为 props /}

{/ 也可以直接传递字面量 /}

);
}
“`

5.2 接收 Props

在函数组件中,props 作为函数的第一个参数被接收,它是一个对象,包含了父组件传递的所有属性。

“`jsx
// ChildComponent.js
function ChildComponent(props) {
console.log(props); // { message: “…”, userData: {…} } 或 { message: “…” }
return (

{props.message}

{props.userData && ( // 检查 userData 是否存在

User: {props.userData.name}, Age: {props.userData.age}

)}

);
}

export default ChildComponent; // 导出组件以便在其他文件使用
“`

Props 解构: 更常见的做法是使用 ES6 的对象解构来直接获取需要的 props:

“`jsx
// ChildComponent.js (使用解构)
function ChildComponent({ message, userData }) {
console.log(message); // “…”
console.log(userData); // {…} 或 undefined
return (

{message}

{userData && (

User: {userData.name}, Age: {userData.age}

)}

);
}

export default ChildComponent;
“`
解构让代码更简洁易读。

5.3 Props 的特点

  • 只读: Props 是父组件给子组件的“礼物”,子组件只能使用,不能直接修改。如果子组件需要改变基于 props 的状态,应该通过其他方式(如 State 或父组件传递的回调函数)实现。
  • 单向数据流: 数据总是从父组件流向子组件。这是 React 推崇的数据流方向,有助于应用状态的管理和调试。

第六章:State – 组件的内部状态管理

State 是组件内部管理的数据,这些数据是可变的,并且会影响组件的渲染。当 State 发生变化时,组件会重新渲染。

6.1 State 的概念

思考一个计数器组件,它需要记住当前的计数值。这个计数值就是组件的 State。当用户点击按钮时,计数值 State 会改变,然后组件会更新显示新的数值。

6.2 在函数组件中使用 State (useState Hook)

在函数组件中,我们使用 useState 这个 Hook 来声明和管理 State。Hook 是 React 16.8 引入的新特性,它允许你在不编写 class 的情况下使用 state 和其他 React 特性。

useState Hook 接收 State 的初始值作为参数,并返回一个包含两个元素的数组:
1. 当前 State 的值。
2. 一个用于更新 State 的函数。

“`jsx
import React, { useState } from ‘react’; // 需要从 react 导入 useState

function Counter() {
// 声明一个名为 count 的 state 变量,并初始化为 0
// setCount 是一个更新 count 的函数
const [count, setCount] = useState(0);

const handleIncrement = () => {
// 使用 setCount 函数更新 state
// React 会接收新的值,并安排组件重新渲染
setCount(count + 1);
};

return (

You clicked {count} times

);
}

export default Counter;
“`

6.3 更新 State

永远不要直接修改 State 变量(如 count = count + 1;)。必须使用 useState 返回的更新 State 的函数(如 setCount)。这是因为 React 需要通过这个函数来追踪 State 的变化,并触发组件的重新渲染。

State 的更新可能是异步的。如果你需要基于前一个 State 值来更新 State,传递一个函数给 State 更新函数会更安全:

jsx
setCount(prevCount => prevCount + 1); // prevCount 是最新的 State 值

6.4 State 的特点

  • 组件私有: State 属于定义它的组件,其他组件无法直接访问。
  • 可变: State 是组件内部管理的可变数据。
  • 触发重新渲染: 当 State 发生变化时,React 会自动重新渲染该组件及其子组件。
  • 初始值只生效一次: useState(initialValue) 中的 initialValue 只在组件初次渲染时起作用。后续的重新渲染会忽略这个初始值。

第七章:事件处理

在 React 中处理事件(如点击、输入、鼠标移动等)与在 HTML 中有些类似,但有一些重要的区别。

7.1 事件命名和语法

  • 驼峰命名: React 事件名采用驼峰命名法,而不是 HTML 的小写(如 onClick 而不是 onclick)。
  • 传递函数: 你传递的是一个 JavaScript 函数作为事件处理器,而不是一个字符串(如 <button onclick="alert('hello')">)。

jsx
<button onClick={handleClick}> {/* 注意是大写的 C */}
Click me
</button>

7.2 事件对象

React 的事件处理器接收一个合成事件对象 (SyntheticEvent)。这是一个跨浏览器兼容的事件对象,它封装了原生浏览器事件,并提供了相同的接口(如 event.targetevent.preventDefault()event.stopPropagation() 等)。

“`jsx
function handleClick(event) {
// event 是合成事件对象
console.log(‘Button clicked!’, event);
event.preventDefault(); // 阻止表单提交等默认行为
}


“`

7.3 传递参数给事件处理器

有时你需要在调用事件处理器时传递额外的参数,例如在一个列表中知道是哪个项目被点击了。你可以使用箭头函数来实现:

“`jsx
function ListItem({ item }) {
const handleClick = (event) => {
console.log(‘Clicked item:’, item.id, event);
};

// 使用箭头函数包裹事件处理器,并在其中调用实际的函数,并传递参数
return (

  • {item.text}
  • );
    }

    // 在父组件中渲染列表
    function ItemList({ items }) {
    return (

      {items.map(item => (

      ))}

    );
    }
    “`

    第八章:条件渲染

    在 React 中,你可以根据不同的条件渲染不同的元素或组件。

    8.1 使用 JavaScript 的 if/else

    你可以直接在函数组件内部使用 JavaScript 的 if/else 语句来决定返回哪个 JSX:

    jsx
    function Greeting({ isLoggedIn }) {
    if (isLoggedIn) {
    return <h1>Welcome back!</h1>;
    } else {
    return <h1>Please sign up.</h1>;
    }
    }

    8.2 使用逻辑 && 运算符

    当你想在条件为真时渲染某个元素,否则什么都不渲染时,可以使用逻辑 && 运算符:

    jsx
    function Mailbox({ unreadMessages }) {
    return (
    <div>
    <h1>Hello!</h1>
    {/* 只有当 unreadMessages 大于 0 时才显示下面的段落 */}
    {unreadMessages > 0 &&
    <h2>
    You have {unreadMessages} unread messages.
    </h2>
    }
    </div>
    );
    }

    在 JavaScript 中,如果 && 的左侧表达式为真,它会返回右侧表达式的值。在 JSX 中,如果右侧是一个 React 元素,它会被渲染出来。如果左侧为假,整个表达式为假,React 会忽略并跳过渲染它(例如 false, 0, '', null, undefined 都不会被渲染)。

    8.3 使用三元运算符

    当需要在两个不同的结果之间进行选择时,三元运算符 (condition ? expr1 : expr2) 是一个简洁的选择:

    jsx
    function UserStatus({ isLoggedIn }) {
    return (
    <div>
    The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
    {isLoggedIn
    ? <LogoutButton />
    : <LoginButton />
    }
    </div>
    );
    }

    第九章:列表渲染

    渲染列表(如数组)是前端开发中常见的任务。在 React 中,我们通常使用 JavaScript 数组的 map() 方法来处理列表渲染。

    9.1 使用 map() 方法

    map() 方法遍历数组中的每个元素,并对每个元素执行一个函数,返回一个新数组。我们可以让这个函数为每个数据项返回一个 React 元素(通常是 JSX):

    “`jsx
    function NumberList({ numbers }) {
    const listItems = numbers.map((number) =>
    // 为列表中的每个项目返回一个

  • 元素
  • {number}
  • );

    return (

      {listItems}

    );
    }

    const numbers = [1, 2, 3, 4, 5];
    // 使用组件
    //
    “`

    更常见的做法是直接在 JSX 中嵌入 map() 调用的结果:

    jsx
    function NumberList({ numbers }) {
    return (
    <ul>
    {/* 直接在 JSX 中映射数组 */}
    {numbers.map((number) =>
    <li key={number.toString()}>{number}</li> // !!! 重要:需要 key !!!
    )}
    </ul>
    );
    }

    9.2 key 的重要性

    当你渲染列表时,每个列表项必须拥有一个独一无二的 key 属性。

    • 为什么需要 key? React 使用 key 来识别列表中哪些项被改变、添加或删除了。它帮助 React 高效地更新列表,而不是重新渲染整个列表。这对于性能至关重要。
    • key 的值: key 属性应该是列表中每个项的唯一稳定标识符。最好的 key 是数据项本身的 ID。如果数据没有 ID,可以使用数组元素的索引作为 key,但不推荐这样做,尤其是在列表顺序可能改变、列表项可能被添加/删除时,因为这可能导致性能问题或显示错误。

    “`jsx
    // 推荐:使用数据项的 ID 作为 key
    const todos = [
    { id: 1, text: ‘Learn React’ },
    { id: 2, text: ‘Build an app’ },
    { id: 3, text: ‘Deploy to server’ }
    ];

    function TodoList({ todos }) {
    return (

      {todos.map(todo =>

    • {/ 使用 todo.id 作为 key /}
      {todo.text}
    • )}

    );
    }
    “`

    第十章:展望与进阶

    通过上面的学习,你已经掌握了 React 的基础知识:JSX、组件、Props、State、事件处理、条件渲染和列表渲染。这些是构建 React 应用的核心。

    接下来,你可以继续深入学习以下内容,以构建更复杂、更健壮的应用:

    • Hooks (useEffect, useContext 等): 掌握更多常用的 Hooks,它们能让你在函数组件中处理副作用(如数据请求、订阅)和使用 Context API 等高级特性。
    • Context API: 用于跨组件层级共享数据,避免 Props drilling(层层传递 props)。
    • 状态管理库: 对于大型应用,可能需要使用更强大的状态管理方案,如 Redux 或 MobX,或者 React 官方推荐的 Recoil。
    • 路由: 学习如何使用 React Router 等库来处理应用的页面导航。
    • 数据请求: 如何在 React 组件中优雅地进行 API 数据请求(使用 useEffect Hook,或 SWR/React Query 等数据请求库)。
    • 组件生命周期: 理解组件在挂载、更新和卸载过程中的不同阶段(对于函数组件主要是通过 useEffect 来模拟和管理)。
    • 样式: 学习更多关于 React 组件样式的方法(CSS Modules, Styled Components 等)。
    • 测试: 如何对 React 组件进行单元测试和集成测试。
    • TypeScript: 将静态类型引入 React 项目,提高代码健壮性。
    • 下一代框架: 了解和学习基于 React 的全栈框架,如 Next.js 或 Remix,它们提供了服务器渲染、路由、API 路由等更多开箱即用的功能。

    总结

    本文带你从零开始认识了 React,理解了它的核心概念,包括声明式 UI、组件化、虚拟 DOM 和 JSX。我们学习了如何搭建开发环境,创建并运行第一个 React 应用,并详细讲解了组件、Props、State、事件处理、条件渲染和列表渲染这些基础而重要的知识点。

    掌握这些基础是迈入 React 世界的第一步。前端技术的学习是一个持续的过程,最重要的是实践。尝试修改 CRA 创建的默认文件,动手构建一些简单的组件,比如一个待办事项列表、一个简单的计算器、一个图片展示组件等等。在实践中你会遇到问题,通过查阅官方文档、搜索和请教,你的理解会越来越深入。

    祝你在 React 的学习之旅中取得成功!不断练习,持续探索,你一定能成为一名优秀的 React 开发者。

    发表评论

    您的邮箱地址不会被公开。 必填项已用 * 标注

    滚动至顶部