快速掌握React:基础知识入门 – wiki基地


快速掌握React:基础知识入门

欢迎来到React的世界!React是Facebook(现Meta)开发并维护的一个用于构建用户界面的JavaScript库。它以其高效、灵活和声明式的特性,迅速成为前端开发领域最受欢迎的技术之一。无论你是前端新手,还是拥有其他框架经验的开发者,掌握React都能极大地提升你构建复杂、交互性强的Web应用的能力。

本文将带你从零开始,深入理解React的核心基础知识。我们将涵盖为什么选择React、如何搭建环境、核心概念(组件、JSX、State、Props)以及如何处理事件和渲染列表。读完本文,你将对React的基础架构有一个扎实全面的认识,并能够开始构建自己的React应用。

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

在深入技术细节之前,我们先来了解一下React的魅力所在。市面上有众多前端框架和库,React为何脱颖而出?

  1. 声明式编程 (Declarative Programming): 这是React最核心的理念之一。你只需要描述你希望用户界面呈现出的最终状态,React会负责处理所有底层的DOM操作,以达到这个状态。这与传统的命令式编程(需要手动一步步告诉浏览器如何修改DOM)形成鲜明对比。声明式使得代码更易于理解、预测和调试。当你需要更新UI时,你只需更新数据,React会自动高效地更新UI。

  2. 组件化 (Component-Based): React推崇将复杂的UI拆分成独立、可复用的组件。每个组件管理自己的状态,并可以通过props(属性)接收父组件传递的数据。这种模块化的开发方式极大地提高了代码的组织性、可维护性和复用性。想象一下构建一个网页就像搭乐高积木,每个积木就是一个组件。

  3. 虚拟DOM (Virtual DOM): 直接操作浏览器真实的DOM是昂贵且低效的。React引入了虚拟DOM的概念。虚拟DOM是真实DOM在内存中的一个轻量级表示。当组件的状态发生变化时,React会先更新虚拟DOM,然后通过一个称为“协调”(Reconciliation)的过程,比较新旧虚拟DOM的差异,找出需要更新的最小部分,最后只对真实DOM进行必要的修改。这大大提高了应用的性能。

  4. 一次学习,随处编写 (Learn Once, Write Anywhere): React不仅用于Web开发,还可以通过React Native构建原生移动应用(iOS和Android)。这使得拥有React技能的开发者可以在不同平台间转移知识,提高了效率。

  5. 强大的生态系统和社区: React拥有庞大且活跃的社区,这意味着你可以轻松找到大量的学习资源、第三方库和解决方案。同时,Facebook的持续投入也保证了React的不断发展和创新。

了解了这些优势,你是否对学习React充满期待了呢?

第二章:搭建你的第一个React环境

要开始编写React代码,你需要一个合适的开发环境。最简单快捷的方式是使用现代化的脚手架工具,它们可以帮助你快速设置一个功能齐全的React项目,包括构建工具(如Webpack或Vite)、代码转译(Babel)、热重载等。

目前主流的React项目创建工具有两种:

  1. Create React App (CRA): 官方提供的工具链,功能齐全,无需配置,适合初学者快速上手。虽然稍显老旧且构建速度相对慢,但依然是稳定可靠的选择。
  2. Vite: 一个更轻量级、构建速度极快的下一代前端工具。对于新的React项目,Vite通常是更好的选择。

我们这里以Vite为例进行演示,因为它更为现代高效。

前提条件:

  • 你需要在你的电脑上安装 Node.js(建议LTS版本)。Node.js包含了npm(Node包管理器),我们将用它来安装React和相关工具。你可以在 Node.js官网 下载安装。
  • 安装完成后,在命令行中运行 node -vnpm -v(或 yarn -v 如果你使用yarn,或 pnpm -v 如果你使用pnpm)来验证安装是否成功。

使用Vite创建React项目:

打开你的命令行工具(如终端、命令提示符或VS Code的集成终端),运行以下命令:

bash
npm create vite@latest my-react-app --template react

  • npm create vite@latest: 使用npm执行create-vite工具的最新版本。
  • my-react-app: 这是你的项目文件夹名称,你可以替换成任何你喜欢的名字。
  • --template react: 指定使用React模板来创建项目。如果你想使用TypeScript,可以使用 --template react-ts

运行命令后,根据提示完成项目创建。通常会问你是否使用TypeScript,选择no即可(如果刚开始学习,建议先用JavaScript)。

项目创建成功后,进入项目文件夹并安装依赖:

bash
cd my-react-app
npm install

安装完成后,你就可以启动开发服务器了:

bash
npm run dev

这会在本地启动一个开发服务器,通常在 http://localhost:5173/(端口号可能不同)。在浏览器中打开这个地址,你应该能看到一个默认的React应用页面。

现在,你的第一个React开发环境已经搭建好了,你可以打开 my-react-app 文件夹,用你喜欢的代码编辑器(如VS Code)开始探索项目结构并编写代码了。

第三章:核心概念一:组件(Components)

组件是React应用的基石。简单来说,一个组件就是一个独立的、可复用的UI片段。它可以是一个按钮、一个导航栏、一个产品卡片,甚至整个页面。

React中主要有两种类型的组件:

  1. 函数组件 (Functional Components): 这是目前React推荐使用的组件类型。它们是简单的JavaScript函数,接收一个props(属性)对象作为参数,并返回React元素(通常是JSX)。

    “`jsx
    // 一个简单的函数组件
    function WelcomeMessage() {
    return

    Hello, React!

    ;
    }

    // 在其他组件中使用它
    function App() {
    return (

    {/ 像HTML标签一样使用组件 /}

    This is my first React app.

    );
    }
    “`

  2. 类组件 (Class Components): 这是React早期使用的组件类型。它们是ES6的类,需要继承自 React.Component,并且必须包含一个 render() 方法,该方法返回React元素。类组件有自己的生命周期方法和管理状态的方式(稍后会讲)。

    “`jsx
    // 一个简单的类组件
    import React from ‘react’; // 类组件需要导入React

    class WelcomeMessageClass extends React.Component {
    render() {
    return

    Hello, React Class Component!

    ;
    }
    }

    // 使用类组件
    function AppClass() {
    return (

    Using a class component.

    );
    }
    “`

为什么函数组件更受欢迎?

自从React引入Hooks(Hook是函数,允许你在函数组件中使用state和其他React特性,而无需编写类)之后,函数组件变得更加强大和灵活。它们通常比类组件更简洁、易于阅读和测试。因此,在现代React开发中,我们强烈推荐使用函数组件。本文后续的示例也将主要使用函数组件。

如何使用组件?

你可以在其他组件的JSX中像使用HTML标签一样使用你定义的组件。注意,自定义的React组件名称必须以大写字母开头,而标准的HTML元素(如div, span, h1)则以小写字母开头。这是React区分组件和原生DOM元素的约定。

组件的组合是构建复杂UI的关键。你可以将多个小组件组合成一个大组件,大组件再组合成页面。

第四章:核心概念二:JSX

在前文的组件示例中,你可能已经注意到了一种看起来像HTML,但又写在JavaScript代码里的语法。这就是JSX (JavaScript XML)

JSX是什么?

JSX是React团队发明的一种JavaScript的语法扩展。它允许你在JavaScript代码中书写类似HTML的结构。它并不是标准的JavaScript或HTML,最终会被Babel等工具转译成普通的JavaScript函数调用(React.createElement())。

为什么使用JSX?

  • 直观: 使用JSX可以非常直观地描述UI的层级结构,比纯粹的JavaScript对象结构更易读。
  • 表达力强: 你可以在JSX中嵌入JavaScript表达式,这使得动态渲染内容变得非常简单。
  • 安全性: React在渲染JSX之前会默认对嵌入的值进行转义,这有助于防止跨站脚本攻击(XSS)。

JSX的基本规则:

  1. 单一根元素: 每个JSX表达式必须只有一个最外层的父元素包裹。你可以使用一个divspan或其他HTML元素作为根,或者使用一个Fragment (<>...),它不会在DOM中生成额外的节点。

    “`jsx
    // 正确
    function MyComponent() {
    return (

    Title

    Content

    );
    }

    // 使用Fragment (推荐,避免多余的div)
    function AnotherComponent() {
    return (
    <>

    Section

    More Content

    );
    }

    // 错误 – 缺少单一根元素
    // function InvalidComponent() {
    // return (
    //

    Title

    //

    Content

    // 两个并列的根元素
    // );
    // }
    “`

  2. 嵌入JavaScript表达式: 使用花括号 {} 在JSX中嵌入JavaScript变量、表达式或函数调用。

    “`jsx
    function Greeting(props) {
    const userName = props.name || ‘Guest’; // 可以使用JS变量
    const isLoggedIn = true; // 可以使用JS变量

    return (

    {/ 嵌入JS变量 /}

    Hello, {userName}!

      {/* 嵌入JS表达式 */}
      <p>Today is {new Date().toLocaleDateString()}.</p>
    
      {/* 嵌入函数调用结果 */}
      <p>{isLoggedIn ? 'Welcome Back!' : 'Please Log In.'}</p>
    </div>
    

    );
    }
    “`

  3. 属性使用驼峰命名法 (camelCase): HTML属性在JSX中大部分是相同的,但少数需要遵循JavaScript的命名规范,使用驼峰命名法。例如:

    • class -> className (因为 class 是JavaScript的关键字)
    • for -> htmlFor (因为 for 是JavaScript的关键字)
    • 事件处理函数如 onclick -> onClick, onchange -> onChange 等。

    jsx
    <button className="my-button" onClick={handleClick} htmlFor="inputField">
    Click Me
    </button>

  4. 自闭合标签: 如果一个元素没有子元素,可以使用自闭合标签,例如 <img />, <br />, <input />。标准HTML标签也可以自闭合(如 <div /> 虽然不常用,但语法上是允许的),但必须以斜杠 / 结尾。

    jsx
    <div>
    <img src="logo.png" alt="Logo" />
    <br />
    <input type="text" />
    </div>

掌握JSX的语法是编写React组件的关键一步。记住,它只是JavaScript的一种语法糖,最终会被工具处理成浏览器能够理解的普通JavaScript。

第五章:核心概念三:State(状态)

在React应用中,有些数据是会随着用户交互或其他事件而变化的,并且这些变化会影响到UI的呈现。这些可变的数据就称为状态 (State)

例如:
* 一个计数器应用中的当前计数值。
* 一个待办事项列表应用中的事项列表。
* 一个开关组件的开/关状态。
* 一个表单输入框中的当前文本内容。

在函数组件中使用State – useState Hook:

在现代React开发中,我们使用 useState Hook 来给函数组件添加状态。useState 是一个React提供的内置Hook。

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

function Counter() {
// 声明一个状态变量 ‘count’ 和更新它的函数 ‘setCount’
// useState(0) 表示状态的初始值为 0
const [count, setCount] = useState(0);

const handleIncrement = () => {
// 使用setCount函数更新状态
// 调用setCount会触发组件重新渲染
setCount(count + 1);
};

const handleDecrement = () => {
setCount(count – 1);
};

return (

Current Count: {count}

{/ 在JSX中显示状态 /}

);
}
“`

useState 的工作原理:

  • useState() 接收一个参数,表示状态的初始值。这个初始值只在组件第一次渲染时有效。
  • useState() 返回一个数组,包含两个元素:
    1. 当前的状态值 (count)。
    2. 一个用于更新状态的函数 (setCount)。
  • 我们使用数组解构 (const [count, setCount] = ...) 来方便地获取这两个元素。
  • 当你调用状态更新函数 (setCount) 时,React会重新渲染这个组件,并将最新的状态值传递给组件函数。
  • 重要: 永远不要直接修改状态变量(如 count = count + 1;)。必须使用状态更新函数来修改状态。直接修改不会触发组件重新渲染,导致UI不更新。
  • 状态更新可能是异步的。如果你需要在状态更新后立即执行某些依赖于新状态的代码,可以使用 useEffect Hook(稍后简单提及)或状态更新函数的函数式更新形式(如 setCount(prevCount => prevCount + 1))。对于简单的更新,直接传值通常足够。

State是React组件“记忆”并响应用户交互的基础。理解State的概念以及如何正确使用 useState 是掌握React的关键一步。

第六章:核心概念四:Props(属性)

React中的Props (Properties) 是父组件向子组件传递数据的方式。组件的Props是只读的,子组件不应该修改接收到的Props。Props使得组件可以根据外部提供的数据呈现不同的内容或行为,增加了组件的灵活性和复用性。

想象一下Props就像是给函数传递参数。

如何传递Props:

在父组件的JSX中,当你使用子组件时,可以将数据作为属性传递:

“`jsx
// 父组件 App.js
import React from ‘react’;
import Greeting from ‘./Greeting’; // 导入子组件

function App() {
const userName = “Alice”;
const userAge = 30;

return (

My App

{/ 将 userName 和 userAge 作为 props 传递给 Greeting 组件 /}

{/ 也可以传递字面量或其他类型的值 /}

);
}

export default App;
“`

如何接收Props:

在函数子组件中,Props会作为第一个参数(一个对象)被接收:

“`jsx
// 子组件 Greeting.js
import React from ‘react’;

// 方法1:直接接收 props 对象
// function Greeting(props) {
// // 从 props 对象中访问属性
// const name = props.name || ‘Guest’;
// const age = props.age;
// const message = props.message || ‘Nice to meet you!’;

// return (
//

Hello, {name}! {age ? You are ${age} years old. : ”} {message}

// );
// }

// 方法2:使用对象解构直接获取需要的属性 (推荐)
function Greeting({ name, age, message = ‘Nice to meet you!’ }) { // 可以设置默认值
const displayName = name || ‘Guest’; // 再次处理默认值或做其他逻辑

return (

Hello, {displayName}! {age ? You are ${age} years old. : ”} {message}

);
}

export default Greeting;
“`

Props的特点:

  • 自上而下传递: Props总是从父组件流向子组件。数据流是单向的。
  • 只读性: 子组件接收到的Props是只读的。子组件不能直接修改Props的值。如果子组件需要响应Props的变化来更新自身,它通常会结合State来实现(例如,用Props的初始值来初始化自己的State)。
  • 任何数据类型: Props可以传递任何JavaScript数据类型,包括字符串、数字、布尔值、数组、对象,甚至是函数或React元素。

Props是实现组件间通信和定制组件外观行为的主要方式。它与State共同构成了React组件数据的两大来源。State管理组件内部随时间变化的数据,而Props用于接收外部(父组件)传递的固定或变化的数据。

第七章:事件处理

React中的事件处理与原生DOM事件类似,但有一些React的特殊之处:

  1. 事件命名: React事件采用驼峰命名法,而不是全小写。例如,onclick 变为 onClickonchange 变为 onChange
  2. 事件处理函数: 你传递一个函数作为事件处理器的值,而不是一个字符串(例如,在HTML中 <button onclick="alert('Hello')">)。
  3. 事件对象: React会给你的事件处理函数传递一个合成事件对象 (SyntheticEvent)。这是一个跨浏览器兼容的事件对象,它封装了原生事件,提供了统一的接口。

如何处理事件:

“`jsx
import React, { useState } from ‘react’;

function EventExample() {
const [message, setMessage] = useState(“Click the button!”);

// 事件处理函数
const handleClick = (event) => {
// event 是合成事件对象
console.log(“Button clicked!”, event);
setMessage(“Button was clicked!”);
};

const handleInputChange = (event) => {
// 通过 event.target.value 获取输入框的当前值
setMessage(Input value: ${event.target.value});
};

return (

Event Handling

{message}

  {/* 直接将函数名作为事件处理函数 */}
  <button onClick={handleClick}>Click Me</button>

  {/* 处理输入框变化事件 */}
  <input type="text" onChange={handleInputChange} placeholder="Type something..." />
</div>

);
}
“`

向事件处理函数传递参数:

有时你需要在调用事件处理函数时传递额外的参数。你可以使用箭头函数来包裹事件处理函数:

“`jsx
function ItemList() {
const items = [‘Apple’, ‘Banana’, ‘Cherry’];

const handleDeleteItem = (itemToDelete) => {
console.log(Deleting item: ${itemToDelete});
// 实际应用中会在这里更新状态来移除项目
};

return (

    {items.map(item => (

  • {item}
    {/ 使用箭头函数包裹,以便在点击时调用 handleDeleteItem 并传递 item 参数 /}
  • ))}

);
}
“`

通过箭头函数 () => handleDeleteItem(item),我们在点击时执行一个匿名函数,该匿名函数再去调用 handleDeleteItem 并传入当前的 item 作为参数。

第八章:列表渲染和Keys

在React中,你经常需要渲染列表数据,比如一个待办事项列表、产品列表等。你可以使用JavaScript的数组方法(如 map(), filter(), reduce())来处理数据,然后将结果渲染到JSX中。最常用的是 map() 方法,因为它能将数组中的每个元素转换为对应的React元素。

“`jsx
function TodoList() {
const todos = [
{ id: 1, text: ‘Learn React Basics’, isCompleted: false },
{ id: 2, text: ‘Build a small app’, isCompleted: false },
{ id: 3, text: ‘Explore advanced topics’, isCompleted: false },
];

return (

    {/ 使用 map() 方法遍历数组,为每个元素生成一个

  • 元素 /}
    {todos.map(todo => (
    // 重要: 每个列表项都应该有一个唯一的 key 属性

  • {todo.text}
  • ))}

);
}
“`

关于 key Prop:

当你渲染列表时,React会要求你为列表中的每个元素(通常是你使用 map() 返回的JSX元素)添加一个特殊的 key 属性。

为什么需要 key

key 是React用于识别列表中哪些元素被改变、添加或删除的一种方式。当列表发生变化时,React使用 key 来高效地更新DOM。没有 key 或者 key 不稳定(例如使用数组索引),React在更新列表时可能会表现不佳,导致性能问题,甚至可能出现意想不到的UI错误或状态问题。

key 的最佳实践:

  • 使用稳定、唯一的ID: 最理想的 key 是数据项本身带有的稳定唯一标识符(例如数据库记录的ID)。
  • 避免使用数组索引作为key: 除非列表是静态的、不会改变(不会新增、删除或重新排序),否则不应该使用数组元素的索引作为 key。因为当列表发生变化时,索引会改变,导致React无法正确追踪元素的身份。

jsx
// 这是一个不好的例子,避免在动态列表中使用索引作为 key
// {todos.map((todo, index) => (
// <li key={index}> {/* 避免这样做 */}
// {todo.text}
// </li>
// ))}

正确使用 key 是列表渲染中至关重要的一点,它直接影响到React应用的性能和正确性。

第九章:简单的实践示例:一个计数器

现在,让我们将前面学到的组件、State、事件处理等概念结合起来,构建一个简单的计数器应用。

“`jsx
import React, { useState } from ‘react’;

function Counter() {
// 1. 使用 useState 定义一个状态变量 count,初始值为 0
const [count, setCount] = useState(0);

// 2. 定义一个事件处理函数来增加计数
const handleIncrement = () => {
// 调用 setCount 更新状态,使其加 1
setCount(count + 1);
};

// 3. 定义一个事件处理函数来减少计数
const handleDecrement = () => {
// 调用 setCount 更新状态,使其减 1
setCount(count – 1);
};

// 4. 定义一个事件处理函数来重置计数
const handleReset = () => {
// 调用 setCount 将状态重置为 0
setCount(0);
};

// 5. 返回 JSX 结构
return (

Simple Counter

{/ 在 JSX 中显示当前状态 count /}

Current Count: {count}

{/ 将事件处理函数绑定到按钮的 onClick 事件 /}


);
}

export default Counter;
“`

在你的 App.js 或其他父组件中导入并使用这个 Counter 组件:

“`jsx
import React from ‘react’;
import Counter from ‘./Counter’; // 确保路径正确

function App() {
return (

My Counter App

{/ 渲染 Counter 组件 /}

);
}

export default App;
“`

运行 npm run dev 启动应用,你就能看到一个功能完整的简单计数器了。这个例子虽然简单,但它包含了React核心基础的State管理和事件响应,是理解React交互逻辑的绝佳起点。

第十章:更进一步:生命周期与副作用 (useEffect)

在类组件中,有许多生命周期方法(如 componentDidMount, componentDidUpdate, componentWillUnmount),允许你在组件的不同阶段执行代码。在函数组件中,我们使用 useEffect Hook 来处理这些“副作用”(Side Effects)。

副作用是指那些不直接用于计算渲染结果的操作,例如:

  • 数据获取 (Fetching data from an API)
  • 订阅外部数据源
  • 手动改变DOM
  • 设置定时器或处理计时器

useEffect 接受两个参数:

  1. 一个包含副作用逻辑的函数。
  2. 一个依赖项数组(可选)。

“`jsx
import React, { useState, useEffect } from ‘react’;

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

// 使用 useEffect Hook 处理数据获取副作用
useEffect(() => {
// 副作用函数
const fetchData = async () => {
try {
setLoading(true);
// 模拟数据获取延迟
await new Promise(resolve => setTimeout(resolve, 1000));
// 假设根据 userId 获取数据
const result = { id: userId, name: User ${userId}, details: Details for user ${userId} };
setData(result);
} catch (err) {
setError(err);
} finally {
setLoading(false);
}
};

fetchData();

// 可选的清理函数:在组件卸载或依赖项改变前执行
return () => {
  console.log(`Cleaning up for userId: ${userId}`);
  // 例如:取消订阅、清除定时器等
};

// 依赖项数组:告诉 React 什么时候重新运行这个 effect
// 如果 userId 变化了,effect 会重新执行

}, [userId]); // 依赖项数组包含 userId

if (loading) return

Loading data…

;
if (error) return

Error loading data: {error.message}

;
if (!data) return null; // 没有数据且不加载也不出错,可能还在初始化

return (

User Details:

ID: {data.id}

Name: {data.name}

{data.details}

);
}
“`

useEffect 的依赖项数组:

  • 空数组 []: Effect 只在组件第一次渲染后运行一次(类似于类组件的 componentDidMount)。
  • 省略依赖项数组: Effect 在每次渲染后都运行(包括初次渲染)。
  • 包含变量 [var1, var2]: Effect 在初次渲染后运行,并且在依赖项数组中的任何变量发生变化时重新运行。这是最常见的用法,确保副作用与组件的状态或Props同步。
  • 返回一个函数: Effect 函数可以返回一个“清理”函数。这个清理函数会在组件卸载前或在下一次Effect运行前执行,用于取消订阅、清除定时器等,防止内存泄漏。

useEffect 是函数组件处理副作用和模拟生命周期行为的关键。虽然它比类组件的生命周期方法更灵活强大,但理解其依赖项数组和清理函数的工作原理需要一些时间。

总结与下一步

恭喜你!你已经掌握了React最核心的基础知识:

  • React的声明式和组件化思想
  • 使用Vite搭建开发环境
  • 函数组件的定义和使用
  • JSX语法及其规则
  • 使用 useState Hook管理组件状态
  • 使用Props在组件间传递数据
  • 处理用户事件
  • 渲染列表以及 key 的重要性
  • 使用 useEffect 处理副作用

这些基础是你构建任何React应用的起点。要真正掌握React,你还需要大量的实践。尝试自己构建一些小应用,例如:

  • 一个简单的待办事项列表(Todo List)
  • 一个计算器
  • 一个简单的画廊,展示图片列表
  • 一个表单,包含输入验证

在实践中遇到问题时,查阅React官方文档 (https://reactjs.org/,现在是 https://react.dev/ 新版文档更友好))、Stack Overflow 或其他技术社区资源。

下一步可以学习的主题:

  • Hooks 进阶: 学习其他常用的Hooks,如 useContext, useReducer, useRef, useMemo, useCallback 等。
  • 组件通信: 除了Props,学习如何使用Context API或第三方库(如Redux, Zustand)进行更复杂的跨组件通信或全局状态管理。
  • 路由: 学习如何使用React Router库处理页面间的导航。
  • 数据获取: 学习更健壮的数据获取模式,例如使用 useEffect 结合异步函数,或使用专门的数据获取库(如TanStack Query/React Query, SWR)。
  • 表单处理: 学习如何在React中更有效地处理复杂表单。
  • 样式: 学习在React中应用样式的不同方法(CSS Modules, Styled Components, Tailwind CSS等)。
  • 性能优化: 学习如何使用 React.memo, useMemo, useCallback 等优化组件渲染性能。

React是一个不断发展的生态系统,但其核心理念相对稳定。扎实掌握基础,不断实践和学习新的工具和模式,你就能快速成长为一名熟练的React开发者。祝你学习顺利,编程愉快!

发表评论

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

滚动至顶部