当前位置: 首页 > news >正文

React的基础API介绍(一)

目录

    • useEffect
      • 1. 替代生命周期方法
      • 2. 副作用管理
      • 3. 依赖项数组
      • 4. 多次使用
      • 5. 与闭包配合
      • 6. 支持异步操作
      • 7. 减少样板代码
    • 注意事项
    • useEffetct是如何拿到变量count最新的值?
      • 1. 每次渲染都会创建新的函数作用域
      • 2. 闭包捕获最新的状态值
      • 3. useEffect 的执行时机
    • useLayoutEffect 与 useEffect
      • 1. useLayoutEffect:
      • 2. useEffect:
    • createRef和useRef
      • 1. createRef
      • 2. useRef
      • 特性对比

useEffect

useEffect 是 React 中的一个 Hook,用于在函数组件中处理副作用操作,例如数据获取、订阅事件、手动修改 DOM 等。以下是 useEffect 的一些主要特性和优点:

1. 替代生命周期方法

模拟类组件的生命周期:useEffect 可以模拟类组件的 componentDidMount、componentDidUpdate 和 componentWillUnmount 方法,允许在组件的不同阶段执行相应的逻辑。

useEffect(() => {// componentDidMount 和 componentDidUpdate 的逻辑return () => {// componentWillUnmount 的逻辑};
}, [dependencies]);

2. 副作用管理

处理副作用:useEffect 在组件渲染后执行,用于处理需要在渲染后发生的副作用,例如更新 DOM、设置订阅、发送网络请求等。

清理副作用:
a. 组件卸载时(Unmount):当组件从界面上被移除时,React 会调用 useEffect 返回的清除函数。这确保了任何与该组件相关的订阅、计时器或其他副作用在组件不再存在时被正确清理。

b. 在重新执行 effect 之前:如果 useEffect 的依赖项数组中的某个值发生了变化,React 会在重新执行 effect 之前调用上一次 effect 的清除函数。这避免了副作用的累积,并确保每次 effect 执行前的环境是干净的。

useEffect(() => {const subscription = someService.subscribe();return () => {subscription.unsubscribe();};
}, []);

3. 依赖项数组

精确控制 effect 执行时机:依赖项数组 [dependencies] 允许你指定 effect 何时重新执行。只有当数组中的依赖项发生变化时,effect 才会被触发。空数组的话只执行一次,相当于componentDidMount

避免不必要的更新:通过正确设置依赖项数组,可以避免不必要的 effect 执行,提高组件性能。

useEffect(() => {// 仅当 count 变化时执行
}, [count]);

4. 多次使用

拆分逻辑:可以在同一个组件中多次使用 useEffect,每个 effect 钩子可以处理不同的副作用逻辑,保持代码清晰。

useEffect(() => {// 处理订阅逻辑
}, []);useEffect(() => {// 处理数据获取逻辑
}, [dataId]);

5. 与闭包配合

访问最新的 state 和 props:useEffect 内部的函数会捕获到当前渲染周期的 state 和 props,确保副作用操作基于最新的数据。

6. 支持异步操作

处理异步任务:useEffect 可以轻松处理异步操作,如数据获取和定时器。

useEffect(() => {async function fetchData() {const result = await axios.get('/api/data');setData(result.data);}fetchData();
}, []);

7. 减少样板代码

简化代码结构:相比于类组件的生命周期方法,useEffect 在函数组件中使用更加简洁,减少了样板代码,使代码更易读。

优点总结

简洁性:使函数组件能够方便地管理副作用,减少了对类组件的依赖。
可读性:通过拆分不同的 useEffect,逻辑更清晰,代码更易于维护。
性能优化:通过依赖项数组,避免了不必要的副作用执行,提高了应用性能。
一致性:提供了统一的方式来处理组件的副作用,减少了认知负担。

注意事项

  1. 正确使用依赖项数组:确保在依赖项数组中包含所有在 effect 中使用的外部变量,防止因为闭包导致的状态不一致问题。
  2. 避免无限循环:如果不慎遗漏依赖项,或者依赖项数组变化过于频繁,可能导致 effect 无限执行,造成性能问题。
  3. 清理函数的重要性:对于订阅、计时器等副作用,一定要在清理函数中进行清理,防止内存泄漏。

示例代码

import React, { useState, useEffect } from 'react';function ChatRoom({ roomId }) {const [messages, setMessages] = useState([]);useEffect(() => {// 订阅聊天信息const subscription = ChatAPI.subscribeToRoom(roomId, (newMessage) => {setMessages((prevMessages) => [...prevMessages, newMessage]);});// 清理函数,取消订阅return () => {ChatAPI.unsubscribeFromRoom(roomId, subscription);};}, [roomId]); // 当 roomId 变化时,重新订阅return (<div>{messages.map((message) => (<p key={message.id}>{message.content}</p>))}</div>);
}

在上述示例中:

使用了 useEffect 来订阅和取消订阅聊天信息。
依赖项数组 [roomId] 确保当房间 ID 变化时,重新执行 effect。
返回的清理函数确保在组件卸载或 roomId 变化时,取消之前的订阅。

useEffetct是如何拿到变量count最新的值?

示例:

function Counter() {  const [count, setCount] = useState(0);    useEffect(() => {   document.title = `You clicked ${count} times`;  });  return (    <div>      <p>You clicked {count} times</p>      <button onClick={() => setCount(count + 1)}>        Click me      </button>   </div>  );
}

useEffect 中的函数能够读取到最新的 count 状态值,主要是由于 JavaScript 中的闭包机制和 React 函数组件的渲染逻辑。

1. 每次渲染都会创建新的函数作用域

新的渲染上下文:在 React 中,每当组件的状态或属性发生变化时,组件都会重新渲染。对于函数组件来说,这意味着组件函数会被重新执行,生成新的渲染结果。
新的变量和函数:每次渲染都会创建新的作用域,其中的变量(如 count)和函数(如传递给 useEffect 的函数)都是新的。

2. 闭包捕获最新的状态值

闭包机制:JavaScript 中,函数会捕获其外部作用域中使用的变量。这意味着在每次渲染时,useEffect 中的函数都会捕获到当次渲染时的 count 值。
最新的 count 值:由于 count 是在组件函数执行时定义的,每次渲染都会得到最新的状态值。useEffect 中的函数在被调用时,使用的就是这个最新的 count 值。

3. useEffect 的执行时机

在渲染后执行:useEffect 中的函数会在组件渲染到屏幕后执行。即使它在渲染期间定义,但执行是在 DOM 更新之后。
每次渲染后执行:在您的示例中,由于没有指定依赖项数组,useEffect 会在每次渲染后执行,因此每次都会使用最新的 count 值。

综合解释

  1. 函数组件的特性:函数组件在每次渲染时都会重新执行函数体,生成新的 count、setCount,以及新的 useEffect 中的函数。
  2. 闭包捕获:useEffect 中的函数在定义时,捕获了当次渲染的 count 值。当 effect 被执行时,它使用的就是这个捕获的值。
  3. 最新的状态值:由于每次渲染都会生成新的 count,useEffect 中的函数总是能够获取到最新的 count 值。

useLayoutEffect 与 useEffect

1. useLayoutEffect:

在浏览器完成布局和绘制之前同步执行。
适用于需要读取布局信息并同步修改 DOM 的场景。
会阻塞浏览器绘制,影响性能,谨慎使用。

2. useEffect:

在浏览器绘制之后异步执行。
不会阻塞渲染,更常用。
示例场景:

使用 useLayoutEffect:测量 DOM 元素的尺寸或位置,然后立即修改布局。

createRef和useRef

1. createRef

创建方式:React.createRef()。

适用于:主要在 类组件(Class Components) 中使用。

示例:

import React from 'react';class MyComponent extends React.Component {constructor(props) {super(props);this.myRef = React.createRef();}componentDidMount() {// 通过 this.myRef.current 访问 DOM 元素或子组件实例console.log(this.myRef.current);}render() {return <div ref={this.myRef}>Hello World</div>;}
}

每次调用 createRef() 都会返回一个新的 Ref 对象。这意味着如果在函数组件中使用 createRef,每次渲染都会创建一个新的 Ref,而不是持久化的。
适用于类组件:在类组件的构造函数中创建一次 Ref,并在整个组件生命周期中保持一致。

2. useRef

创建方式:const refContainer = useRef(initialValue)。

适用于:函数组件(Function Components),因为它是一个 Hook。

示例:

import React, { useRef, useEffect } from 'react';function MyComponent() {const myRef = useRef(null);useEffect(() => {// 通过 myRef.current 访问 DOM 元素或保存任何可变值console.log(myRef.current);}, []);return <div ref={myRef}>Hello World</div>;
}

useRef 返回的 Ref 对象在整个组件生命周期中是持久的。无论组件如何重新渲染,useRef 返回的对象始终指向同一个引用。
不仅可以用于获取 DOM 元素,还可以用于保存任意可变值,类似于在类组件中使用实例属性。
不会在组件重新渲染时重新初始化。

特性对比

特性createRefuseRef
适用组件类型类组件(Class Components)函数组件(Function Components)
调用时机通常在构造函数中调用一次在函数组件内的任意位置(遵循 Hook 规则)
每次渲染是否创建新 Ref是,每次调用都会创建新的 Ref 对象否,useRef 返回的对象在整个生命周期中保持不变
用途获取 DOM 元素或子组件实例获取 DOM 元素、保存可变值、存储任何可变数据
可持久化的可变值否,主要用于引用 DOM 或组件实例是,可用于存储任意可变值,不会触发重新渲染

http://www.mrgr.cn/news/71030.html

相关文章:

  • GRU (门控循环单元 - 基于RNN - 简化LSTM又快又好 - 体现注意力的思想) + 代码实现 —— 笔记3.5《动手学深度学习》
  • SpringBoot学习记录(六)配置文件参数化
  • FairGuard游戏加固实机演示
  • C# 中的事件和委托:构建响应式应用程序
  • 大数据新视界 -- 大数据大厂之 Hive 数据导入:多源数据集成的策略与实战(上)(3/ 30)
  • springboot课程答疑系统(代码+数据库+LW)
  • 第12课 二维数组(1)
  • 世界职院技能大赛视角下,高职高专技能人才高阶素养培育路径探究
  • CRM系统用户满意度调查:哪些品牌最受欢迎
  • 量化交易系统开发-实时行情自动化交易-3.4.1.4.A股衍生数据
  • Spring资源加载模块,原来XML就这,活该被注解踩在脚下 手写Spring第六篇了
  • 浅谈c++函数调用以及析构函数为虚函数的原因
  • 基于Ubuntu2410脚本搭建OpenStack-D版
  • 青训5_1112_01 小S的倒排索引(内置方法 set(a) set(b) 及sorted 排序)
  • No module named ‘torch.nn.attention‘
  • 【C++】C++基础知识
  • 期权懂|你知道场外个股期权该如何参与吗?
  • 微服务改造:踩过的坑!
  • 2. Sharding-JDBC广播表和绑定表操作
  • 阿里云Linux安装Docker服务报错问题
  • 【轻松远程处理图片:在线图片编辑工具Photopea群晖NAS部署解决方案】
  • 解决 C/C++ 中 “invalid use of incomplete type” 编译错误
  • 【前端】深入浅出的React.js详解
  • Spring Boot编程训练系统:深入设计与实现
  • 双指针算法的妙用:提高代码效率的秘密(3)
  • 【三宝的身高】