学习 React【Plan - June - Week 1】

一、使用 JSX 书写标签语言

JSX 是一种 JavaScript 的语法扩展,React 使用它来描述用户界面。


什么是 JSX?

  • JSX 是 JavaScript 的一种语法扩展。
  • 看起来像 HTML,但它实际上是在 JavaScript 代码中写 XML/HTML。
  • 浏览器并不能直接运行 JSX,需要通过打包工具(如 Babel)将其转译为 JavaScript。

示例:

js 复制代码
const element = <h1>Hello, world!</h1>;

1、JSX 的基本规则

使用大写字母定义组件

js 复制代码
function MyButton() {
  return <button>I'm a button</button>;
}
  • 小写字母开头的标签,如 <div> 被解析为 HTML 标签。
  • 大写字母开头的标签,如 <MyButton> 被解析为 React 组件。

必须使用闭合标签

  • 所有标签必须闭合(类似 XML 语法)
js 复制代码
// 正确
<input />
<br />
<MyComponent />

// 错误
<input>

使用 {} 插入 JavaScript 表达式

js 复制代码
const user = "小明";
const element = <h1>Hello, {user}!</h1>;
  • 只能插入表达式(不是语句)

合法表达式:

js 复制代码
{1 + 2}
{user.name}
{formatDate(date)}

非法语句:

js 复制代码
{if (isTrue) { ... }}
{for (...) { ... }}

使用 className 代替 class

js 复制代码
// HTML 写法
<div class="container"></div>

// JSX 写法
<div className="container"></div>

因为 class 是 JavaScript 的关键字,所以要使用 className


使用 camelCase 的属性名

js 复制代码
// HTML 写法
<input tabindex="0" onclick="handleClick()" />

// JSX 写法
<input tabIndex={0} onClick={handleClick} />

2、条件渲染和列表渲染

条件渲染

使用三元表达式、逻辑与 &&

js 复制代码
{isLoggedIn ? <LogoutButton /> : <LoginButton />}

{messages.length > 0 && <Notification messages={messages} />}

列表渲染

使用 map() 进行循环输出,并为每个子元素设置唯一的 key

js 复制代码
const items = ['A', 'B', 'C'];

<ul>
  {items.map(item => <li key={item}>{item}</li>)}
</ul>

3、JSX 转换成 JavaScript 的原理

JSX 会被转译为 React.createElement 调用:

js 复制代码
const element = <h1 className="title">Hello</h1>;

// 会被转换为:
const element = React.createElement('h1', { className: 'title' }, 'Hello');

4、组合 JSX

JSX 支持嵌套结构:

js 复制代码
function App() {
  return (
    <div>
      <Header />
      <Content />
      <Footer />
    </div>
  );
}

可使用片段(Fragment)避免多余的 DOM 元素:

js 复制代码
<>
  <td>内容1</td>
  <td>内容2</td>
</>

5、JSX Tips

注释写法:

js 复制代码
{/* 这是注释 */}

多行 JSX 需要用括号包裹:

js 复制代码
return (
  <div>
    <h1>Hello</h1>
  </div>
);

二、组件(Component)

React 应用是由组件构成的,组件是可以复用的 UI 单元。


什么是组件?

  • 组件(Component) 是 React 的核心概念。
  • 本质上是一个返回 JSX 的函数。
  • 组件名称必须以大写字母开头。

示例:

js 复制代码
function MyButton() {
  return <button>I'm a button</button>;
}

在 JSX 中使用:

js 复制代码
export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
    </div>
  );
}

组件命名规则

  • 必须以大写字母开头,否则会被当成 HTML 标签。
  • 使用 PascalCase 命名约定(每个单词首字母大写)。

1、组件是函数,不是标签

js 复制代码
function MyButton() {
  return <button>Click me</button>;
}

这个 MyButton 是一个函数,而 <MyButton /> 是它的使用方式(调用)


2、组件可以复用

你可以多次使用同一个组件,它们是互相独立的:

js 复制代码
function MyApp() {
  return (
    <div>
      <MyButton />
      <MyButton />
    </div>
  );
}

每个 <MyButton /> 都会渲染一个独立的按钮。


3、组件的结构建议

建议为每个组件建一个文件(例如 MyButton.jsx),用于项目组织:

bash 复制代码
src/
├─ components/
│  └─ MyButton.jsx
└─ App.jsx

🧪 示例代码汇总

js 复制代码
// MyButton.jsx
export default function MyButton() {
  return <button>I'm a button</button>;
}

// App.jsx
import MyButton from './MyButton';

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

三、State

React 的状态(state)允许组件"记住"信息。状态是让组件有"记忆"的机制,通常用于跟踪用户交互或界面变化。


1、什么是状态(State)?

  • 状态是组件的"记忆"
  • 在每次重新渲染时,组件的状态保持不变
  • 状态的变化会 触发组件的重新渲染

2、如何添加状态?

通过 useState Hook:

js 复制代码
import { useState } from 'react';

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

useState 解释:

js 复制代码
const [state, setState] = useState(initialValue);
名称 含义
state 当前状态值
setState 用于更新状态的函数
initialValue 初始状态值

3、状态的基本用法示例

js 复制代码
import { useState } from 'react';

export default function MyButton() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

4、每次点击发生了什么?

  1. 点击按钮时,handleClick 被调用。
  2. setCount(count + 1) 更新状态。
  3. React 重新渲染组件。
  4. 新的 count 显示在界面上。

状态更新不会改变当前值,而是触发一次新的渲染 ,组件中的 count 会更新为新值。


5、状态在组件之间是隔离的

每个组件实例有自己独立的状态。

js 复制代码
<MyButton />
<MyButton />

上面两个按钮互不影响,即使它们使用相同的 useState


6、不要直接修改 state 变量

js 复制代码
// 错误写法(不会触发重新渲染)
count = count + 1;

// 正确写法
setCount(count + 1);

只有通过 setCount 这样的更新函数,React 才会触发重新渲染。


7、多个状态变量

可以在一个组件中使用多个 useState

js 复制代码
const [count, setCount] = useState(0);
const [name, setName] = useState('React');

8、示例完整代码

js 复制代码
import { useState } from 'react';

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

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      Clicked {count} times
    </button>
  );
}

export default function MyApp() {
  return (
    <div>
      <h1>Welcome to my app</h1>
      <MyButton />
      <MyButton />
    </div>
  );
}

四、响应事件

React 使用类似 HTML 的方式来处理用户交互事件,比如点击、输入、悬停等。但语法略有不同,并支持更强的逻辑功能。


1、事件绑定基础

React 使用 onClickonChange 等属性来绑定事件处理函数。

示例:

js 复制代码
function MyButton() {
  function handleClick() {
    alert('你点击了我!');
  }

  return (
    <button onClick={handleClick}>
      点击我
    </button>
  );
}

注意:

  • 使用驼峰命名(如 onClick,而不是 onclick
  • 事件处理函数是一个普通的 JavaScript 函数
  • JSX 中不使用字符串绑定函数(不同于 HTML 的 onclick="handleClick()"

2、为什么使用函数名而不是函数调用?

js 复制代码
// 正确
onClick={handleClick}

// 错误(会立即执行)
onClick={handleClick()}

你应传递函数的引用,而不是函数的执行结果。


3、使用箭头函数传参

有时你希望传递参数给事件处理函数,可以使用箭头函数:

js 复制代码
function handleClick(name) {
  alert(`Hello, ${name}!`);
}

<button onClick={() => handleClick('小明')}>
  Say Hello
</button>

4、在组件中组合事件处理逻辑

React 鼓励你将组件拆成小块,事件处理函数可以在组件内部定义或向下传递:

js 复制代码
function Button({ onClick, children }) {
  return <button onClick={onClick}>{children}</button>;
}

function App() {
  function handleClick() {
    alert('Clicked!');
  }

  return (
    <div>
      <Button onClick={handleClick}>按钮1</Button>
      <Button onClick={handleClick}>按钮2</Button>
    </div>
  );
}

5、常见事件类型

React 事件名 对应 HTML 说明
onClick onclick 点击事件
onChange onchange 输入/选择改变
onSubmit onsubmit 表单提交
onMouseEnter onmouseenter 鼠标进入
onKeyDown onkeydown 按键按下

6、阻止默认行为

可以在事件中调用 event.preventDefault()

js 复制代码
function handleSubmit(e) {
  e.preventDefault();
  alert('提交已阻止');
}

<form onSubmit={handleSubmit}>
  <button type="submit">提交</button>
</form>

7、React 与原生 DOM 事件的区别

项目 React 原生 HTML
命名方式 驼峰命名,如 onClick 小写,如 onclick
传递方式 传函数引用 传字符串或函数调用
自动阻止冒泡 否,你仍需手动阻止冒泡 同样需手动处理

8、示例完整代码

js 复制代码
function Button({ message, children }) {
  function handleClick() {
    alert(message);
  }

  return (
    <button onClick={handleClick}>
      {children}
    </button>
  );
}

export default function App() {
  return (
    <div>
      <Button message="你好!">点我</Button>
      <Button message="再见!">再点我</Button>
    </div>
  );
}

五、React 哲学

"React 哲学" 教你如何从 UI 设计图开始,一步步将页面拆解为组件,再构建出数据驱动的交互式界面。


示例场景简介

我们要实现一个可搜索的商品表格(Searchable Product Table),它包含:

  • 一个搜索框
  • 一个是否只显示有库存商品的勾选框
  • 一个根据品类分组的商品表格

构建步骤总览

React 官方建议采用 五步法

  1. 将 UI 拆解为组件层级结构
  2. 构建组件的静态版本(无交互)
  3. 确定最小但完整的 UI 状态表示
  4. 确定哪些组件拥有状态(状态提升)
  5. 添加反向数据流(处理用户输入)

1、第一步:将 UI 拆解为组件层级

观察 UI,并根据界面结构拆出以下组件:

组件层级结构

txt 复制代码
FilterableProductTable (父组件)
├─ SearchBar
└─ ProductTable
   ├─ ProductCategoryRow
   └─ ProductRow

每个组件的职责

组件名 作用描述
FilterableProductTable 管理所有状态,整合其他组件
SearchBar 输入搜索文本与是否过滤库存
ProductTable 接收数据与过滤条件,渲染表格
ProductCategoryRow 显示每个品类的标题
ProductRow 显示单个商品

2、第二步:构建静态版本(无交互)

  • 使用父组件 FilterableProductTable 将假数据通过 props 传给子组件。
  • 每个组件只关注如何显示数据,不包含状态或交互。
  • 假数据示例:
js 复制代码
const PRODUCTS = [
  {category: "Fruits", price: "$1", stocked: true, name: "Apple"},
  {category: "Fruits", price: "$1", stocked: true, name: "Dragonfruit"},
  {category: "Fruits", price: "$2", stocked: false, name: "Passionfruit"},
  {category: "Vegetables", price: "$2", stocked: true, name: "Spinach"},
  {category: "Vegetables", price: "$4", stocked: false, name: "Pumpkin"},
  {category: "Vegetables", price: "$1", stocked: true, name: "Peas"}
];

3、第三步:确定最小但完整的 UI 状态(State)

根据界面交互功能,确定需要驱动 UI 的状态

  • 搜索文本(filterText
  • 是否只显示有库存商品(inStockOnly

不是状态的内容(可由 props 或其他状态推导得出):

  • 商品数据(是静态的)
  • 分类标题(可从数据中提取)
  • 筛选后的商品列表(由 filterText + inStockOnly 计算)

4、第四步:决定状态的归属

状态应该放在最"靠上的共同祖先组件"中。

状态名 所属组件 原因
filterText FilterableProductTable SearchBar 和 ProductTable 都使用它
inStockOnly FilterableProductTable 同上

5、第五步:添加反向数据流(提升状态 + 子传父)

SearchBar 接收 filterTextinStockOnly 作为 props,并通过 onChange 回调将用户输入传递给父组件修改状态。

js 复制代码
function SearchBar({ filterText, inStockOnly, onFilterTextChange, onInStockChange }) {
  return (
    <form>
      <input
        type="text"
        value={filterText}
        onChange={(e) => onFilterTextChange(e.target.value)}
        placeholder="Search..."
      />
      <label>
        <input
          type="checkbox"
          checked={inStockOnly}
          onChange={(e) => onInStockChange(e.target.checked)}
        />
        Only show products in stock
      </label>
    </form>
  );
}

6、组件结构(最终)

js 复制代码
<FilterableProductTable products={PRODUCTS} />

// 内部包含
  └── <SearchBar
         filterText={...}
         inStockOnly={...}
         onFilterTextChange={...}
         onInStockChange={...}
       />

  └── <ProductTable
         products={...}
         filterText={...}
         inStockOnly={...}
       />

学习资料来源

使用 JSX 书写标签语言
第一个组件
State
响应事件
React 哲学

相关推荐
xiaofeichaichai4 小时前
Webpack
前端·webpack·node.js
问心无愧05134 小时前
ctf show web入门111
android·前端·笔记
唐某人丶4 小时前
模型越来越强,我们还需要 Agent 工程吗?—— 从价值重估到 Harness 实践
前端·agent·ai编程
智码看视界4 小时前
现代Web开发基础:全栈工程师的起航点
前端·后端·c5全栈
JS菌4 小时前
手写一个 AI Agent 全栈项目:从沙箱执行到子智能体的完整实现
前端·人工智能·后端
excel6 小时前
HLS TS 文件损坏的元凶:Git 提交与拉取
前端
Aphasia3116 小时前
https连接传输流程
前端·面试
徐小夕6 小时前
万字长文!千万级文档 RAG 知识库系统落地实践
前端·算法·github
threelab6 小时前
Three.js 物理模拟着色器 | 三维可视化 / AI 提示词
开发语言·前端·javascript·人工智能·3d·着色器