react中的useState和Hook、副作用

react的组件分为类组件和函数组件,Hook 是一种特殊的函数,可以让你在函数组件中使用类组件中才有的一些特性。useState、useEffect、useReducer都是Hook。其中useState用于在函数组件中添加状态,useEffect用于在函数组件中执行副作用,而useReducer则是useState的加强版。在 React 中,“副作用”(side effect)通常指的是那些在组件渲染之外发生的操作,即那些不直接参与 UI 渲染的行为。这些副作用可以包括数据获取、订阅服务、记录日志、修改 DOM、设置定时器等任何与组件渲染本身无关的操作。

一、useState

react、vue这类框架,我看都属于单页面应用(SPA)。也就是,所有的内容呈现,都在一张页面中完成。我们所看到的其中千变万化,内有乾坤,都是javascript控制的结果。javascript改变页面中变量或元素的值,页面需要重新渲染才能反映最新结果。那么如何才能让页面重新渲染反映最新结果呢,在vue中,大概就是要将变量声明为所谓响应式,比如

const state = reactive({v1:0,v2:false
})

而在react中,就稍有点复杂。react也是组件式开发,但它的组件分为类组件和函数组件。类组件出现时间较早,较为笨重,函数组件是后来才有的,相对较为轻盈,且越来越流行。当然,类组件也不可或缺,各自有适用场景。比如当需要用到生命周期事件时,就要使用类组件。比如组件加载完毕就怎样怎样,组件卸载又如何如何,诸如此类。

react中,如果是类组件,使用 this.state 来定义组件的状态,使用 this.setState() 方法来更新状态。如果是函数组件则使用useState来设置状态。

1、类组件中控制状态

import React, { Component } from 'react';class Counter extends Component {constructor(props) {super(props);this.state = {count: 0};this.handleIncrement = this.handleIncrement.bind(this);this.handleReset = this.handleReset.bind(this);}handleIncrement() {this.setState(prevState => ({count: prevState.count + 1}));}handleReset() {this.setState({ count: 0 });}render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.handleIncrement}>Increment</button><button onClick={this.handleReset}>Reset</button></div>);}
}export default Counter;

2、函数组件中使用useState控制状态

useState 接受一个参数作为初始状态,并返回一个包含两个元素的数组:

import React, { useState } from 'react';function Example() {// 设置初始状态为 0const [count, setCount] = useState(0);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

二、useReducer

useReducer是useState的威力加强版(也就是说,它也只用在函数组件中)。useReducer 通常用于替代 useState,当状态逻辑变得更加复杂时,使用 useReducer 可以让代码更易于理解和维护。

useReducer 接受一个 reducer 函数和一个初始状态作为参数,并返回一个包含当前状态和一个 dispatch 函数的数组。其中reducer函数是自定义的,主要是根据参数来设置各个状态值。也就是说,useState设置一个状态值,而useReducer可以设置多个状态值。而dispatch函数则负责执行reducer函数。(真绕啊)

import React, { useReducer } from 'react';function counterReducer(state, action) {switch (action.type) {case 'increment':return { count: state.count + 1 };case 'decrement':return { count: state.count - 1 };case 'reset':return { count: 0 };default:throw new Error();}
}function Counter() {const [state, dispatch] = useReducer(counterReducer, { count: 0 });return (<div><p>Count: {state.count}</p><button onClick={() => dispatch({ type: 'increment' })}>Increment</button><button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button><button onClick={() => dispatch({ type: 'reset' })}>Reset</button></div>);
}export default Counter;

三、useEffect

useEffect用于在函数组件中执行副作用操作。副作用可以包括数据获取、订阅服务、记录日志、直接操作 DOM 等与渲染本身不直接相关的操作。

1、类组件执行副作用操作

类组件可以通过生命周期方法来处理副作用,例如:

componentDidMount 用于在组件挂载后执行副作用。
componentDidUpdate 用于在组件更新后执行副作用。
componentWillUnmount 用于在组件卸载前清理副作用。

2、函数组件中执行副作用操作

函数组件,可以使用 useEffect Hook 来处理副作用。useEffect就是类组件中上述三个生命周期方法(componentDidMount 、componentDidUpdate、componentWillUnmount)的综合体。

useEffect 接受一个回调函数作为第一个参数,该回调函数会在组件渲染之后执行。它还可以接受一个可选的依赖项数组作为第二个参数,该数组定义了哪些变量的变化会导致副作用回调重新运行。

import React, { useState, useEffect } from 'react';function Example() {const [count, setCount] = useState(0);useEffect(() => {document.title = `You clicked ${count} times`;// 清理副作用return () => {document.title = 'React App';};}, [count]); // 依赖项数组,只在 count 改变时运行return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}

当 useEffect 的依赖项数组为空时,这意味着副作用回调函数仅会在组件挂载完成后运行一次,并且在组件卸载前运行清理函数(如果有的话)。这是因为空数组 [] 表示没有任何依赖项,所以副作用回调不会因为任何状态或属性的变化而重新运行。

import React, { useEffect } from 'react';function Example() {useEffect(() => {console.log('Component mounted');// 设置一个定时器const timer = setInterval(() => {console.log('Timer tick');}, 1000);// 清理副作用return () => {console.log('Component will unmount');clearInterval(timer); // 清除定时器};}, []); // 依赖项为空数组return (<div><p>Hello, World!</p></div>);
}

四、Hook

1、Hook专属于类组件

在 React 中,Hooks 是一种允许在函数组件中使用状态和其他 React 特性的机制。Hooks 使得函数组件能够具有与类组件相同的功能,同时保持代码的简洁性和可读性。

2、Hooks 的规则

为了确保 Hooks 正确工作,需要遵循以下规则:

只在顶层调用 Hooks:不要在循环、条件或嵌套函数内部调用 Hooks。
只在 React 函数中调用 Hooks:不要在普通的 JavaScript 函数中调用 Hooks。

通过遵循这些规则,可以确保 Hooks 在每次渲染时都按照预期工作,并且状态管理逻辑是可预测的。

3、常用Hooks

一些常用的 Hooks:

useState
用于在函数组件中添加状态。它接受一个初始值,并返回一个状态值和一个更新该状态的方法。

useEffect
用于执行副作用操作,如数据获取、订阅或手动更改 DOM。它类似于类组件中的 componentDidMount、componentDidUpdate 和 componentWillUnmount。

useContext
用于消费 React Context 对象中的值。这比使用 Consumer 组件或 withContext 高阶组件更简洁。

useReducer
类似于 useState,但它允许你使用 Reducer 模式管理状态,这对于复杂的组件状态非常有用。

useCallback
用于返回一个被优化过的函数引用,以避免在每次渲染时创建新的函数。

useMemo
用于缓存昂贵的计算结果,以避免在每次渲染时重新计算。

useRef
创建一个可变的引用对象。它的 .current 属性被初始化为传递的参数(initialValue)。返回的对象将在组件的整个生命周期内保持不变。

useImperativeHandle
自定义暴露给父组件的 ref 的值。

useLayoutEffect
类似于 useEffect,但在所有 DOM 更新完成后同步运行。这使得它适合于布局相关的操作。

五、副作用

在 React 中,术语“副作用”(side effect)用来描述那些不在组件渲染过程中直接发生的操作。换句话说,副作用是指那些在组件的生命周期中执行的、与 UI 渲染逻辑无关的操作。这些操作可能会对应用程序的状态、DOM 或外部系统产生影响。

1、为什么称为“副作用”

副作用这个词来源于函数式编程的概念,在函数式编程中,一个纯粹的函数只依赖于它的输入参数,并且只产生输出而不修改任何外部状态。在这样的环境中,函数不应该有除了返回值之外的任何其他效果。然而,在实际的编程中,特别是在 React 这样的框架中,我们经常需要执行一些非纯粹的操作,比如数据获取、DOM 操作、设置定时器等。这些操作虽然不是纯粹的,但对于应用程序的正常运行是必不可少的。

在 React 中,常见的副作用包括但不限于:

1)数据获取:
从服务器或其他数据源获取数据。
通常在组件加载时或状态/属性发生变化时执行。

2)订阅服务:
订阅 WebSocket、RSS Feed 或其他实时数据流。
在组件卸载时取消订阅以避免内存泄漏。

3)设置定时器:
使用 setTimeout 或 setInterval 来执行延迟或周期性的任务。
在组件卸载时清除定时器以避免内存泄漏。

4)记录日志:
记录用户交互或调试信息。
不直接影响 UI 的渲染过程。

5)直接操作 DOM:
修改页面上的元素,而不是通过 React 的虚拟 DOM。
这种做法一般不推荐,但在某些情况下可能是必需的。

2、为什么需要处理副作用

处理副作用很重要,因为它们有助于组件与外部世界交互,例如从服务器获取数据或更新外部服务的状态。此外,适当的清理副作用也很重要,以避免内存泄漏或不必要的资源消耗。

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

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

相关文章

机器学习 - 随机森林降方差公式推导

背景 在随机森林算法中&#xff0c;我们通过对数据集进行多次采样&#xff08;有放回地抽样&#xff09;并训练多个决策树模型&#xff0c;然后将这些模型的预测结果进行平均来得到最终的预测结果。这样做的一个重要好处是能够降低模型的方差&#xff08;Variance&#xff09;…

高级java每日一道面试题-2024年7月27日-并发篇-Thread类中的yield方法有什么作用?

面试官: Thread类中的yield方法有什么作用? 我回答: Java 的 Thread 类中的 yield 方法是一个线程调度相关的API&#xff0c;它的作用是让当前正在运行的线程放弃CPU时间片&#xff0c;使得其他具有相同优先级的线程有机会被执行。下面我们详细探讨一下 yield 方法的作用和使…

【笔记-软考】层次式架构-业务逻辑层架构设计

Author&#xff1a;赵志乾 Date&#xff1a;2024-07-28 Declaration&#xff1a;All Right Reserved&#xff01;&#xff01;&#xff01; 1. 组件设计 业务逻辑组件包括两部分&#xff1a;接口和实现&#xff0c;其中接口用于定义组件必须实现的方法&#xff0c;其可以让控制…

2399. 检查相同字母间的距离(python3)

两种解法&#xff1a; 第一种&#xff0c;暴力解法&#xff0c;采用双重循环&#xff0c;解决问题&#xff08;时间复杂度较高&#xff09; class Solution:def checkDistances(self, s: str, distance: List[int]) -> bool:n len(s)for i in range(n):for j in range(i …

Hive3:Hive初体验

1、创建表 CREATE TABLE test(id INT, name STRING, gender STRING);2、新增数据 INSERT INTO test VALUES(1, 王力红, 男); INSERT INTO test VALUES(2, 钉钉盯, 女); INSERT INTO test VALUES(3, 咔咔咔, 女);3、查询数据 简单查询 select * from test;带聚合函数的查询 …

论文写作之latex配置(VSCODE+TEXT LIVE)

1.overleaf 初学者学习latex可以用这个练习&#xff0c;可以在线编辑十分方便&#xff0c;但是编译时间受限制 网站&#xff1a;https://www.overleaf.com/project 2.Tex live 选择一个.iso文件下载 网站&#xff1a;Index of /CTAN/systems/texlive/Images/ 下载成功&am…

exuberant ctags 支持 typescript 解析

exuberant ctags 支持 typescript 解析 exuberant ctags 是 GNU ctags 的替代品。 最近在看 nodejs 的项目代码&#xff0c;老规矩用它生成 tags 文件在 vim 中看。 可惜对于项目中的 typescript 文件&#xff0c;无法识别及解析。 查了下是否能让 ctags 支持 typescript 分析…

2024第三届钉钉杯大学生大数据挑战赛【A题】完整分享

2024第三届钉钉杯大学生大数据挑战赛已经开赛&#xff0c;小编给大家带来非常实用的助力【A题】完整&#xff0c;&#xff08;看图片下方的说明&#xff09;&#xff0c;资料预览&#xff1a; 微信公众号

MongoDB流量分析

MongoDB流量分析通常指的是对MongoDB数据库的网络通信量、操作频率、性能指标和资源利用情况进行监控和分析的过程。这有助于理解数据库的负载、性能、潜在的瓶颈和安全状况&#xff0c;以便进行优化和维护。MongoDB流量分析可以涵盖以下几个方面&#xff1a; 网络流量监控&…

react Vant中如何获取步进器的值

在React中使用Vant&#xff08;一个轻量、可靠的移动端Vue组件库&#xff0c;虽然原生是为Vue设计的&#xff0c;但如果你在使用的是React版本的Vant&#xff0c;比如通过某些库或框架桥接Vue组件到React&#xff0c;或者是一个类似命名的React UI库&#xff09;&#xff0c;获…

进阶篇,内附代码:锂电池二阶模型-离线与在线参数辨识

锂电池二阶模型-在线参数辨识 背景二阶等效电路模型介绍二阶模型的离线参数辨识二阶模型的RLS表达式递推代码已知问题背景 锂电池一阶戴维南等效模型的参数辨识方法,已经在前面两期详细地讲解了一轮。 一阶模型-离线参数辨识一阶模型-在线参数辨识本期继续讲解一下如何进行二…

多线程初阶(三)- 线程案例

目录 1.单例模式 &#xff08;1&#xff09;饿汉模式 &#xff08;2&#xff09;懒汉模式 前言 懒汉式1-synchronized加锁 懒汉式2-双重if保障 懒汉式3-volatile防止误判 2.生产者消费者模型 &#xff08;1&#xff09;阻塞队列 &#xff08;2&#xff09;优点 解耦…

@InitBinder 注解

InitBinder 注解 介绍 InitBinder注解可以作用在被Controller注解的类的方法上&#xff0c;表示为当前控制器注册一个属性编辑器&#xff0c;用于对WebDataBinder进行初始化&#xff0c;且只对当前的Controller有效。InitBinder标注的方法会被多次执行的&#xff0c;也就是说…

5万字长文吃透快手大数据面试题及参考答案(持续更新)

目录 Flink为什么用aggregate()不用process() 为什么使用aggregate() 为什么不用process() 自定义UDF, UDTF实现步骤,有哪些方法?UDTF中的ObjectInspector了解吗? 自定义UDF实现步骤 自定义UDTF实现步骤 UDTF中的ObjectInspector Spark Streaming和Flink的区别 Flu…

后端返回列表中包含图片id,如何将列表中的图片id转化成url

问题描述 如果我有一个列表数据&#xff0c;列表中每个对象都包含一个图片id&#xff0c;现在我需要将列表中的图片id转化成图片&#xff0c;然后再页面上显示出来 如果你有一个列表数据&#xff0c;列表中每个对象都包含一个图片 ID&#xff0c;并且你想将这些图片 ID 转化为…

鸿蒙OpenHarmony Native API【结构体】 头文件

OH_Drawing_BitmapFormat Overview Related Modules: [Drawing] Description: 结构体用于描述位图像素的格式&#xff0c;包括颜色类型和透明度类型 Since: 8 Version: 1.0 Summary Public Attributes Public Attribute NameDescriptioncolorFormatalphaFormat De…

在Spring Boot中实现异步处理与并发控制

在Spring Boot中实现异步处理与并发控制 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;是个冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01;今天&#xff0c;我们将深入探讨如何在Spring Boot中实现异步处理与并发控制。这一过程涉及到异步任务的执行、…

QT:控件样式设置误区

当我设置不同控件格式样式&#xff0c;原先的代码如下 //设置MainWindow的背景R颜色this->setStyleSheet("QMainWindow{background-color:#F5F8FD;}");//设置菜单栏字体和背景颜色this->setStyleSheet("QMenuBar{color:#FFFFFF;background-color:#2A579A;…

PlantUML学习笔记-嵌入式系统设计常用图例

在嵌入式系统设计过程中&#xff0c;需要使用一些图例对系统框架及业务流程进行说明&#xff0c;以便于多人协同开发及后期的系统维护&#xff0c;提高团队开发效率。 1. 嵌入式设计开发常使用的图例&#xff1a; 1.1 用例图&#xff08;Use Case Diagram&#xff09; 用例图…

KamaCoder 99. 岛屿数量 + Leetcode 200. Number of Islands

99. 岛屿数量 题目描述&#xff1a; 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。你可以假设矩阵外均被水包围。 输…