学习 Hooks【Plan - June - Week 2】

news2025/6/10 8:58:10

一、React API

React 提供了丰富的核心 API,用于创建组件、管理状态、处理副作用、优化性能等。本文档总结 React 常用的 API 方法和组件。


1. React 核心 API

React.createElement(type, props, …children)

  • 用于创建 React 元素,JSX 会被编译成该函数调用。
  • type:标签名或组件函数
  • props:属性对象
  • children:子节点列表

React.Component

  • React 组件基类,用于创建类组件。
  • 语法:
class MyComponent extends React.Component {
  render() {
    return <div>Hello</div>;
  }
}

React.PureComponent

  • 类组件基类,带浅层比较的性能优化。
  • 如果 props 和 state 没有变化,不会重新渲染。

React.Fragment

  • 用于返回多个子元素的容器,不会产生额外的 DOM 节点。
  • 语法:
<React.Fragment>
  <Child1 />
  <Child2 />
</React.Fragment>

或者简写为:

<>
  <Child1 />
  <Child2 />
</>

2. React Hooks API

useState(initialState)

  • 声明状态变量,返回 [state, setState]

useEffect(effect, deps)

  • 用于副作用操作,类似生命周期。
  • deps 数组决定何时重新执行副作用。

useContext(Context)

  • 订阅 React Context。

useReducer(reducer, initialState)

  • 管理复杂状态,类似 Redux。

useMemo(factory, deps)

  • 缓存计算结果,避免重复计算。

useCallback(callback, deps)

  • 缓存函数引用,避免子组件不必要渲染。

useRef(initialValue)

  • 创建可变引用对象,常用于获取 DOM 或存储变量。

useImperativeHandle(ref, createHandle, deps)

  • 自定义暴露给父组件的实例值。

useLayoutEffect(effect, deps)

  • 与 useEffect 类似,但在 DOM 变更后同步触发。

3. 辅助工具函数

React.cloneElement(element, [props], […children])

  • 克隆并修改已有 React 元素。

React.isValidElement(object)

  • 判断对象是否是有效的 React 元素。

React.Children

  • 工具对象,操作 props.children
    • React.Children.map
    • React.Children.forEach
    • React.Children.count
    • React.Children.only
    • React.Children.toArray

4. 其他重要 API

React.createContext(defaultValue)

  • 创建上下文(Context)。

React.forwardRef(renderFunction)

  • 转发 ref,允许父组件访问子组件 DOM。

React.memo(Component, [areEqual])

  • 组件的性能优化,高阶组件,类似 PureComponent。

React.lazy(factory)

  • 支持代码分割,懒加载组件。

React.Suspense

  • 配合 React.lazy 使用,显示加载状态。

二、useEffect

useEffect 是 React 中管理副作用(side effects)的 Hook。副作用包括数据获取、订阅、手动 DOM 操作等。


1. 基础用法

import React, { useEffect, useState } from 'react';

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

  useEffect(() => {
    // 每次渲染后执行副作用
    document.title = `你点击了 ${count}`;
  });

  return (
    <div>
      <p>你点击了 {count}</p>
      <button onClick={() => setCount(count + 1)}>
        点击我
      </button>
    </div>
  );
}

2. 参数说明

useEffect(effect: () => (void | (() => void)), deps?: DependencyList)
  • effect:副作用函数,函数内部可以执行副作用代码,且可返回清理函数。
  • deps:依赖数组(可选),用于控制副作用执行的时机。

3. 依赖数组

  • 无依赖数组:副作用在每次组件渲染后执行。
  • 空依赖数组 ([]):副作用只在组件挂载(Mount)和卸载(Unmount)时执行一次。
  • 有依赖项数组:只有当依赖项发生变化时,副作用才执行。

示例:

useEffect(() => {
  console.log('只在挂载和卸载时运行');
}, []);

useEffect(() => {
  console.log('count 发生变化时运行');
}, [count]);

4. 清理副作用

  • effect 函数可以返回一个清理函数,在组件卸载或依赖更新前调用。
useEffect(() => {
  const id = setInterval(() => {
    console.log('定时器运行中');
  }, 1000);

  // 返回清理函数,清除定时器
  return () => clearInterval(id);
}, []);

5. 副作用示例

  • 数据请求(fetch)
  • 事件监听和解绑
  • 订阅和取消订阅
  • 手动 DOM 操作
  • 设置定时器

6. 注意事项

  • 避免无限循环:确保依赖数组正确,防止副作用无限触发。
  • 同步 vs 异步useEffect 不支持直接声明为 async 函数,但可在内部调用异步函数。

示例:

useEffect(() => {
  async function fetchData() {
    const res = await fetch('/api/data');
    const data = await res.json();
    // 处理数据
  }
  fetchData();
}, []);

7. useEffect 与生命周期对应关系

生命周期方法useEffect 变体
componentDidMountuseEffect(() => {}, [])
componentDidUpdateuseEffect(() => {})
componentWillUnmountuseEffect(() => { return () => {} }, [])

8. React 18+ 特别说明

React 18 开启严格模式下,useEffect 会在开发环境中执行两次以帮助发现副作用问题。

9. 示例完整代码

import React, { useState, useEffect } from 'react';

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

  useEffect(() => {
    const timerId = setInterval(() => {
      setCount(c => c + 1);
    }, 1000);

    return () => clearInterval(timerId);
  }, []);

  return <h1>计时器:{count}</h1>;
}

三、useContext

useContext 用于在函数组件中访问 React Context 的值,简化了跨组件传递数据的过程。


1. 什么是 Context?

  • Context 提供了一种在组件树中传递数据的方法,无需通过每一级组件的 props。
  • 适用于主题、语言、认证信息等全局数据。

2. useContext 的用法

const value = useContext(MyContext);
  • MyContext 是通过 React.createContext 创建的 Context 对象。
  • useContext 返回当前 Context 的值,即最近的 <MyContext.Provider> 所提供的值。
  • 当 Provider 的 value 改变时,组件会重新渲染。

3. 创建 Context 示例

import React, { createContext, useContext } from 'react';

// 创建 Context
const ThemeContext = createContext('light');

function Toolbar() {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  // 读取 Context 值
  const theme = useContext(ThemeContext);
  return <button style={{ background: theme === 'dark' ? '#333' : '#ccc' }}>按钮</button>;
}

function App() {
  return (
    // 提供 Context 值
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

4. 注意事项

  • 组件必须在对应 Context 的 Provider 内部,否则使用默认值。
  • 只有当 Context 的值发生变化时,使用该 Context 的组件才会重新渲染。
  • 不要在组件内直接修改 Context 的值,应通过 Provider 传递新的值。

5. 常见使用场景

  • 主题切换(light/dark)
  • 用户认证信息
  • 国际化语言设置
  • 全局配置参数

6. 组合多个 Context

  • 可以多次调用 useContext 读取多个不同的 Context。
const theme = useContext(ThemeContext);
const user = useContext(UserContext);

7. 对比 Context.Consumer

  • useContext 更简洁,适用于函数组件。
  • 类组件中仍可用 <Context.Consumer> 读取 Context。

四、用 Reducer 和 Context 扩展状态管理

当应用变复杂,单纯用 useState 管理状态变得笨重。此时可以使用 useReducer 管理复杂状态逻辑,结合 Context 实现跨组件共享状态,替代 Redux 等库。


1. 为什么用 Reducer?

  • 多个状态相互关联,修改逻辑复杂
  • 需要明确状态变化的过程和原因(动作)
  • 状态逻辑集中,更易维护和测试

2. useReducer 简介

const [state, dispatch] = useReducer(reducer, initialState);
  • state:当前状态
  • dispatch:派发动作(action)
  • reducer:状态变更函数 (state, action) => newState

示例:计数器

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({ type: 'increment' })}>+1</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-1</button>
    </>
  );
}

3. 结合 Context 实现跨组件状态共享

  • statedispatch 放入 Context,供多个组件访问。
  • 这样,父组件可以集中管理状态,子组件通过 useContext 访问和派发动作。
const CountContext = React.createContext();

function CounterProvider({ children }) {
  const [state, dispatch] = useReducer(reducer, { count: 0 });

  return (
    <CountContext.Provider value={{ state, dispatch }}>
      {children}
    </CountContext.Provider>
  );
}

function CounterDisplay() {
  const { state } = React.useContext(CountContext);
  return <div>Count: {state.count}</div>;
}

function CounterButtons() {
  const { dispatch } = React.useContext(CountContext);
  return (
    <>
      <button onClick={() => dispatch({ type: 'increment' })}>+1</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-1</button>
    </>
  );
}

4. 应用结构示例

function App() {
  return (
    <CounterProvider>
      <CounterDisplay />
      <CounterButtons />
    </CounterProvider>
  );
}

5. 优缺点

优点缺点
明确的状态管理流程和结构代码稍显复杂,学习曲线陡峭
集中管理状态,方便维护与测试过度使用可能导致冗余
方便实现复杂状态变化和回退等功能状态共享时 Context 过度更新会导致性能问题

6. 最佳实践

  • 只对需要共享的状态使用 Context 和 Reducer
  • 将逻辑拆分成多个 reducer 和 Context(模块化)
  • 使用 React.memo、useMemo 优化性能
  • 明确 Action 类型和 Payload,写清楚 Reducer 逻辑

以下是 React 官方文档 《井字棋教程 (Tic Tac Toe Tutorial)》 的详细 Markdown 学习笔记整理:


五、React 井字棋教程

通过构建一个经典的井字棋游戏,学习 React 基础知识,包括组件设计、状态管理、事件处理、以及提升组件能力。


1. 项目介绍

  • 井字棋是一个简单的 3 x 3 网格游戏,两名玩家轮流放置 X 和 O。
  • 目标是先在水平、垂直或对角线上连成一条线。
  • 教程通过这个项目介绍 React 的核心概念。

2. 构建游戏的步骤

  1. 创建一个 Square 组件,表示棋盘中的一个格子。
  2. 创建一个 Board 组件,包含 9 个 Square
  3. 维护棋盘状态,响应用户点击。
  4. 判断胜负逻辑。
  5. 添加游戏历史记录,实现时间旅行功能。

3. 组件设计

Square 组件

  • 功能:显示一个按钮,表示一个格子。
  • 接收 props:value (X, O 或 null),onClick 点击事件处理。
function Square({ value, onClick }) {
  return (
    <button className="square" onClick={onClick}>
      {value}
    </button>
  );
}

Board 组件

  • 维护 9 个格子的状态。
  • 渲染 9 个 Square,传入对应的 valueonClick
function Board() {
  const [squares, setSquares] = React.useState(Array(9).fill(null));

  function handleClick(i) {
    const nextSquares = squares.slice();
    nextSquares[i] = 'X';
    setSquares(nextSquares);
  }

  return (
    <div>
      <div className="board-row">
        <Square value={squares[0]} onClick={() => handleClick(0)} />
        {/* 其他格子 */}
      </div>
      {/* 其他行 */}
    </div>
  );
}

4. 状态提升(Lifting State Up)

  • 当需要多个组件共享状态时,将状态提升到它们最近的共同父组件。
  • 在教程中,Board 组件的状态被提升到 Game 组件管理。
  • Game 组件管理历史状态,实现回退功能。

5. 计算游戏胜负

  • 实现一个函数 calculateWinner(squares),判断当前棋盘是否有玩家获胜。
  • 如果获胜,显示胜者信息,游戏结束。
function calculateWinner(squares) {
  const lines = [
    [0,1,2], [3,4,5], [6,7,8],
    [0,3,6], [1,4,7], [2,5,8],
    [0,4,8], [2,4,6]
  ];
  for (let line of lines) {
    const [a,b,c] = line;
    if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
      return squares[a];
    }
  }
  return null;
}

6. 处理用户交互

  • 点击格子时更新状态,切换玩家。
  • 禁止点击已被占用的格子。
  • 游戏结束后禁止继续点击。

7. 时间旅行(历史记录)

  • Game 组件维护棋盘的历史数组。
  • 用户可点击历史按钮,回到之前的任一步骤。
  • 利用数组和状态管理,实现“时间旅行”效果。
function Game() {
  const [history, setHistory] = React.useState([Array(9).fill(null)]);
  const [stepNumber, setStepNumber] = React.useState(0);
  const [xIsNext, setXIsNext] = React.useState(true);

  function handleClick(i) {
    const historyUpToStep = history.slice(0, stepNumber + 1);
    const current = historyUpToStep[historyUpToStep.length - 1];
    const squares = current.slice();
    if (calculateWinner(squares) || squares[i]) return;

    squares[i] = xIsNext ? 'X' : 'O';
    setHistory([...historyUpToStep, squares]);
    setStepNumber(historyUpToStep.length);
    setXIsNext(!xIsNext);
  }

  function jumpTo(step) {
    setStepNumber(step);
    setXIsNext((step % 2) === 0);
  }
  
  // 渲染历史按钮,调用 jumpTo
}

学习资料来源

React 参考
useEffect
useContext
使用 Reducer 和 Context
教程:井字棋游戏

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2406424.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法

目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客&#xff1a;【写在创作纪念日】基于SpringBoot和PostG…

使用VMware克隆功能快速搭建集群

自己搭建的虚拟机&#xff0c;后续不管是学习java还是大数据&#xff0c;都需要集群&#xff0c;java需要分布式的微服务&#xff0c;大数据Hadoop的计算集群&#xff0c;如果从头开始搭建虚拟机会比较费时费力&#xff0c;这里分享一下如何使用克隆功能快速搭建一个集群 先把…

篇章一 论坛系统——前置知识

目录 1.软件开发 1.1 软件的生命周期 1.2 面向对象 1.3 CS、BS架构 1.CS架构​编辑 2.BS架构 1.4 软件需求 1.需求分类 2.需求获取 1.5 需求分析 1. 工作内容 1.6 面向对象分析 1.OOA的任务 2.统一建模语言UML 3. 用例模型 3.1 用例图的元素 3.2 建立用例模型 …

Qt/C++学习系列之列表使用记录

Qt/C学习系列之列表使用记录 前言列表的初始化界面初始化设置名称获取简单设置 单元格存储总结 前言 列表的使用主要基于QTableWidget控件&#xff0c;同步使用QTableWidgetItem进行单元格的设置&#xff0c;最后可以使用QAxObject进行单元格的数据读出将数据进行存储。接下来…

基于django+vue的健身房管理系统-vue

开发语言&#xff1a;Python框架&#xff1a;djangoPython版本&#xff1a;python3.8数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;PyCharm 系统展示 会员信息管理 员工信息管理 会员卡类型管理 健身项目管理 会员卡管理 摘要 健身房管理…

Yolo11改进策略:Block改进|FCM,特征互补映射模块|AAAI 2025|即插即用

1 论文信息 FBRT-YOLO&#xff08;Faster and Better for Real-Time Aerial Image Detection&#xff09;是由北京理工大学团队提出的专用于航拍图像实时目标检测的创新框架&#xff0c;发表于AAAI 2025。论文针对航拍场景中小目标检测的核心难题展开研究&#xff0c;重点解决…

简单聊下阿里云DNS劫持事件

阿里云域名被DNS劫持事件 事件总结 根据ICANN规则&#xff0c;域名注册商&#xff08;Verisign&#xff09;认定aliyuncs.com域名下的部分网站被用于非法活动&#xff08;如传播恶意软件&#xff09;&#xff1b;顶级域名DNS服务器将aliyuncs.com域名的DNS记录统一解析到shado…

循环语句之while

While语句包括一个循环条件和一段代码块&#xff0c;只要条件为真&#xff0c;就不断 循环执行代码块。 1 2 3 while (条件) { 语句 ; } var i 0; while (i < 100) {console.log(i 当前为&#xff1a; i); i i 1; } 下面的例子是一个无限循环&#xff0c;因…

机器学习复习3--模型评估

误差与过拟合 我们将学习器对样本的实际预测结果与样本的真实值之间的差异称为&#xff1a;误差&#xff08;error&#xff09;。 误差定义&#xff1a; ①在训练集上的误差称为训练误差&#xff08;training error&#xff09;或经验误差&#xff08;empirical error&#x…

联邦学习带宽资源分配

带宽资源分配是指在网络中如何合理分配有限的带宽资源&#xff0c;以满足各个通信任务和用户的需求&#xff0c;尤其是在多用户共享带宽的情况下&#xff0c;如何确保各个设备或用户的通信需求得到高效且公平的满足。带宽是网络中的一个重要资源&#xff0c;通常指的是单位时间…

今日行情明日机会——20250609

上证指数放量上涨&#xff0c;接近3400点&#xff0c;个股涨多跌少。 深证放量上涨&#xff0c;但有个小上影线&#xff0c;相对上证走势更弱。 2025年6月9日涨停股主要行业方向分析&#xff08;基于最新图片数据&#xff09; 1. 医药&#xff08;11家涨停&#xff09; 代表标…

GC1808:高性能音频ADC的卓越之选

在音频处理领域&#xff0c;高质量的音频模数转换器&#xff08;ADC&#xff09;是实现精准音频数字化的关键。GC1808&#xff0c;一款96kHz、24bit立体声音频ADC&#xff0c;以其卓越的性能和高性价比脱颖而出&#xff0c;成为众多音频设备制造商的理想选择。 GC1808集成了64倍…

生产管理系统开发:专业软件开发公司的实践与思考

生产管理系统开发的关键点 在当前制造业智能化升级的转型背景下&#xff0c;生产管理系统开发正逐步成为企业优化生产流程的重要技术手段。不同行业、不同规模的企业在推进生产管理数字化转型过程中&#xff0c;面临的挑战存在显著差异。本文结合具体实践案例&#xff0c;分析…

VASP软件在第一性原理计算中的应用-测试GO

VASP软件在第一性原理计算中的应用 VASP是由维也纳大学Hafner小组开发的一款功能强大的第一性原理计算软件&#xff0c;广泛应用于材料科学、凝聚态物理、化学和纳米技术等领域。 VASP的核心功能与应用 1. 电子结构计算 VASP最突出的功能是进行高精度的电子结构计算&#xff…

Centos 7 服务器部署多网站

一、准备工作 安装 Apache bash sudo yum install httpd -y sudo systemctl start httpd sudo systemctl enable httpd创建网站目录 假设部署 2 个网站&#xff0c;目录结构如下&#xff1a; bash sudo mkdir -p /var/www/site1/html sudo mkdir -p /var/www/site2/html添加测试…

从数据报表到决策大脑:AI重构电商决策链条

在传统电商运营中&#xff0c;决策链条往往止步于“数据报表层”&#xff1a;BI工具整合历史数据&#xff0c;生成滞后一周甚至更久的销售分析&#xff0c;运营团队凭经验预判需求。当爆款突然断货、促销库存积压时&#xff0c;企业才惊觉标准化BI的决策时差正成为增长瓶颈。 一…

(12)-Fiddler抓包-Fiddler设置IOS手机抓包

1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求&#xff0c;也可以截获各种智能手机发出的HTTP/ HTTPS 请求。 Fiddler 能捕获Android 和 Windows Phone 等设备发出的 HTTP/HTTPS 请求。同理也可以截获iOS设备发出的请求&#xff0c;比如 iPhone、iPad 和 MacBook 等苹…

第2课 SiC MOSFET与 Si IGBT 静态特性对比

2.1 输出特性对比 2.2 转移特性对比 2.1 输出特性对比 器件的输出特性描述了当温度和栅源电压(栅射电压)为某一具体数值时,漏极电流(集电极电流

MCP和Function Calling

MCP MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09; &#xff0c;2024年11月底&#xff0c;由 Anthropic 推出的一种开放标准&#xff0c;旨在统一大模型与外部数据源和工具之间的通信协议。MCP 的主要目的在于解决当前 AI 模型因数据孤岛限制而…

解密鸿蒙系统的隐私护城河:从权限动态管控到生物数据加密的全链路防护

摘要 本文以健康管理应用为例&#xff0c;展示鸿蒙系统如何通过细粒度权限控制、动态权限授予、数据隔离和加密存储四大核心机制&#xff0c;实现复杂场景下的用户隐私保护。我们将通过完整的权限请求流程和敏感数据处理代码&#xff0c;演示鸿蒙系统如何平衡功能需求与隐私安…