从变量的角度理解 Hooks , 变得更简单了

从变量角度理解Hooks

在React的世界里,Hooks的引入为函数式组件带来了前所未有的灵活性和能力。它们让我们得以完全摆脱class式的写法,在函数式组件中完成生命周期管理、状态管理、逻辑复用等几乎全部组件开发工作。这次,我们就从变量的角度来深入理解一下这些强大的Hooks。

hooks

一、useState:定义自变量

想象一下,我们有一个自变量x,它代表组件的某个状态。在React中,我们可以使用useState来定义这个自变量:

const [x, setX] = useState(0);

这里,x就是我们的自变量,而setX是一个函数,用于改变x的值。

接下来,我们定义一个因变量y,它是x的函数:

const y = 2 * x + 1;

每次x变化时,y都会随之更新。

为了演示这个过程,我们可以创建一个简单的点击事件,每次点击时x增加1:

export default function App() {
  const [x, setX] = useState(0);
  const y = 2 * x + 1;
  const changeX = () => setX(x + 1);
  
  return (
    <ul onClick={changeX}>
      <li>x是{x}</li>
      <li>y是{y}</li>
    </ul>
  );
}

二、useMemo & useCallback:缓存因变量

在上面的例子中,每次组件重新渲染时,ychangeX都会重新计算。但在复杂的业务场景中,这些计算可能会变得非常昂贵。为了优化性能,我们可以使用useMemouseCallback来缓存这些因变量。

useMemo用于缓存一个数据类型的因变量:

//const y = 2 * x + 1;
const y = useMemo(() => 2 * x + 1, [x]);

useCallback则用于缓存一个函数类型的因变量:

//const changeX = () => setX(x + 1);
const changeX = useCallback(() => setX(x + 1), [x]);

这两个Hooks都接收一个创建函数和一个依赖项数组作为参数。只要依赖项不变,它们就会返回缓存的值或函数,从而避免不必要的计算。

三、useEffect:处理副作用

在函数式编程中,副作用是指一个函数在固定的输入下产生不固定的输出。在React中,副作用通常包括修改DOM、发起网络请求、设置定时器等。

为了处理这些副作用,我们可以使用useEffect。它允许我们定义一个函数,在组件渲染后执行副作用逻辑。

例如,我们希望当x变化时,将页面标题修改为x的值:

useEffect(() => {
  document.title = x;
}, [x]);

这里,useEffect接收一个函数和一个依赖项数组。当依赖项变化时,函数会被执行。

四、useReducer:管理复杂状态

当组件的状态变得复杂时,我们可以使用useReducer来管理它们。useReducer可以看作是useState的进阶版,它使用Redux的理念,将多个状态合并为一个状态对象,并通过一个reducer函数来更新状态。

  • useReducer 和 redux 中 reducer 很像
  • useState 内部就是靠 useReducer 来实现的
  • useState 的替代方案,它接收一个形如 (state, action) => newState 的 reducer,并返回当前的 state 以及与其配套的 dispatch 方法
  • 在某些场景下,useReducer 会比 useState 更适用,例如 state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state 等
let initialState = 0;
// 如果你希望初始状态是一个{number:0}
// 可以在第三个参数中传递一个这样的函数 ()=>({number:initialState})
// 这个函数是一个惰性初始化函数,可以用来进行复杂的计算,然后返回最终的 initialState
const [state, dispatch] = useReducer(reducer, initialState, init);

这里,state是我们的状态对象,dispatch是一个函数,用于触发状态更新。

const initialState = 0;
function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {number: state.number + 1};
    case 'decrement':
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function init(initialState){
    return {number:initialState};
}
function Counter(){
    const [state, dispatch] = useReducer(reducer, initialState,init);
    return (
        <>
          Count: {state.number}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
    )
}

五、useContext: 跨组件层级传递自变量

useContext 允许你在组件树中跨多层级访问context(上下文)的值,而无需通过每层手动传递props。以下是对useContext的详细解释:
1、定义与功能

  • 定义:useContext是一个React Hook,用于读取和订阅React组件中的context。
  • 功能:它能够在组件树中共享数据,使得数据可以在不同层级的组件之间传递,而无需通过props逐层传递。

2、使用方式

  1. 创建Context:首先,你需要使用React.createContext()方法创建一个context对象。这个对象不保存数据,但它作为数据的载体,允许你从组件中获取或向组件提供数据。
  2. 提供数据:然后,你需要在组件树中使用Context.Provider包裹那些需要访问context的组件,并通过value属性向Provider提供数据。
  3. 读取数据:在需要访问context的组件中,你可以使用useContext Hook来读取context的值。你需要将先前创建的context对象作为参数传递给useContext。

3、示例

以下是一个简单的示例,展示了如何使用useContext在组件之间共享数据:

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

// 创建一个Context对象
const MyContext = createContext('defaultValue');

function App() {
  // 使用useState创建一个state,并通过Provider将其提供给后代组件
  const [value, setValue] = useState('newValue');
  return (
    <MyContext.Provider value={value}>
      <ChildComponent />
      <ButtonComponent />
    </MyContext.Provider>
  );
}

function ChildComponent() {
  // 在子组件内使用useContext获取context的值
  const contextValue = useContext(MyContext);
  return <div>Child Component: {contextValue}</div>;
}

function ButtonComponent() {
  // 假设这里有一个函数用于修改context的值(实际中可能需要通过某种方式触发这个函数)
  const handleClick = () => {
    // 这里需要一种方式来修改Provider中的value,通常是通过某种状态管理或回调函数实现
    // 例如,可以使用useReducer或其他状态管理库来更新value
  };
  return <button onClick={handleClick}>Change Context Value</button>;
}

export default App;

注意:在这个示例中,ButtonComponent组件需要一种方式来修改Provider中的value。在实际应用中,这通常是通过某种状态管理(如useState、useReducer)或回调函数来实现的。由于这个示例是为了说明useContext的用法,所以并没有展示如何修改value的具体实现。

4、注意事项

(1) Provider嵌套:Provider组件可以嵌套使用,这样你就可以在不同的层级提供不同的context值。
(2) 性能优化:当context的值发生变化时,React会自动重新渲染那些读取了该context的组件。为了避免不必要的重渲染,你可以使用React.memo或shouldComponentUpdate等优化技术。
(3) 默认值:如果在组件树中没有找到对应的Provider,useContext会返回传递给createContext的defaultValue。

总的来说,useContext是React中一个非常有用的Hook,它能够帮助你在组件之间共享数据,从而简化组件间的通信和状态管理。

六、useRef:增加灵活性

最后,useRef作为一个标记变量,提供了一种在组件的整个生命周期内持久存储数据的方法 , 并作用于自变量与因变量的不同路径中。它增加了组件逻辑的灵活性,允许我们在组件的生命周期内持久地存储数据。
以下是对useRef的详细解释:

1、定义与功能

  • 定义:useRef是一个React Hook,它返回一个可变的ref对象,其.current属性被初始化为传递给useRef的参数(在组件的整个生命周期内保持不变)。
  • 功能:useRef主要用于两个场景:访问DOM元素和保存跨渲染周期的变量。

2、使用场景

  1. 访问DOM元素

    • 当需要直接访问DOM元素(如设置焦点、测量尺寸等)时,可以使用useRef。
    • 通过将ref对象传递给元素的ref属性,可以在组件中通过ref.current访问该元素。
  2. 保存跨渲染周期的变量

    • useRef返回的ref对象在组件的整个生命周期内保持不变,因此可以用于存储不需要触发组件重新渲染的变量。
    • 这使得useRef成为保存上一次渲染状态、在自定义Hook中共享数据等场景的理想选择。

3、示例

以下是一个使用useRef访问DOM元素和保存跨渲染周期变量的示例:

import React, { useRef } from 'react';

function AutoFocusInput() {
  // 创建一个ref对象用于访问DOM元素
  const inputRef = useRef(null);

  // 处理按钮点击事件,使输入框获得焦点
  const handleButtonClick = () => {
    inputRef.current.focus();
  };

  // 创建一个ref对象用于保存跨渲染周期的变量
  const counterRef = useRef(0);

  // 增加计数器的值(不会触发组件重新渲染)
  const incrementCounter = () => {
    counterRef.current += 1;
  };

  return (
    <div>
      <input type="text" ref={inputRef} />
      <button onClick={handleButtonClick}>聚焦输入框</button>
      <p>计数器值:{counterRef.current}</p>
      <button onClick={incrementCounter}>增加计数器</button>
    </div>
  );
}

export default AutoFocusInput;

在这个示例中,inputRef用于访问输入框DOM元素,并在按钮点击时使其获得焦点。counterRef用于保存一个计数器变量,并通过按钮点击事件增加其值。由于useRef返回的ref对象在组件的整个生命周期内保持不变,因此可以在多次渲染之间保持计数器的值。

4、注意事项

(1) 不要滥用useRef:虽然useRef可以在不触发组件重新渲染的情况下存储数据,但它不应该被用作主要的状态管理工具。对于需要响应状态变化的数据,应该使用useState或useReducer等状态管理Hook。
(2) 与class组件中的refs对比:在class组件中,refs是通过React.createRef()创建的,并在componentDidMountcomponentDidUpdate等生命周期方法中访问DOM元素。而在函数组件中,useRef提供了一种更简洁的方式来创建和使用refs。

总之,useRef是React中一个非常有用的Hook,它提供了在组件的整个生命周期内持久存储数据的方法,而不会触发组件的重新渲染。这使得它在访问DOM元素和保存跨渲染周期变量等场景中非常有用。

总结

从变量的角度来看,React Hooks的本质是自变量与因变量的关系。useState用于定义自变量,useMemouseCallback用于定义无副作用的因变量,useEffect用于定义有副作用的因变量。为了方便操作更多的自变量,我们有了useReducer;为了跨组件层级操作自变量,我们有了useContext;最后,为了让组件逻辑更灵活,我们有了useRef

通过这些Hooks,我们可以在函数式组件中轻松实现复杂的逻辑和状态管理,享受React带来的高效和便捷。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【面试经典150】day 9

目录 1.Z 字形变换 2.找出字符串中第一个匹配项的下标 3.文本左右对齐 1.Z 字形变换 class Solution {public String convert(String s, int numRows) {//明明是N字形变换if(numRows<2) return s;//rows是可扩展的字符串数组List<StringBuilder>rowsnew ArrayLi…

sudo apt install jupyter-notebook安装notebook失败E: Aborting install.

问题&#xff1a; sudo apt install jupyter-notebook安装notebook失败E: Aborting install. ~/jie/mywork/PointNetCFD$ sudo apt install jupyter-notebook --fix-missing Reading package lists... Done Building dependency tree Reading state information... Do…

软件工程实践项目:人事管理系统

一、项目的需求说明 通过移动设备登录app提供简单、方便的操作。根据公司原来的考勤管理制度&#xff0c;为公司不同管理层次提供相应的权限功能。通过app上面的各种标准操作&#xff0c;考勤管理无纸化的实现&#xff0c;使公司的考勤管理更加科学规范&#xff0c;从而节省考…

AI与低代码的碰撞:企业数字化转型的新引擎

引言 在当今的商业环境中&#xff0c;企业数字化转型已从选择题变成了必答题。面对日益复杂的市场竞争和不断变化的客户需求&#xff0c;传统的开发模式常常显得力不从心——开发周期冗长、技术门槛高、成本居高不下&#xff0c;企业很难快速响应市场变化。而在这种背景下&…

WPF中实现PasswordBox的双向绑定

我们知道一个属性想要实现双向绑定&#xff0c;最基本的便是这个属性需要时依赖属性&#xff0c;但是微软工程师在设计的时候Password并不是依赖属性&#xff0c;那我们想要实现双向绑定该怎么去做呢&#xff1f; 最常用的便是改造PasswordBox,为它增加一个扩展属性&#xff0c…

聚链成网,趣链科技参与 “跨链创新联合体”建设

近日&#xff0c;2024全球数商大会在上海举办。大会由上海数据集团和上海市数商协会联合主办&#xff0c;上海市数据局和浦东新区人民政府支持&#xff0c;以“数联全球&#xff0c;商通未来——‘链’接数字经济新未来”为主题&#xff0c;聚焦区块链技术和应用场景展开。 会上…

记录一次mmpretrain训练数据并转onnx推理

目录 1.前言 2.代码 3.数据形态【分类用】 4.配置文件 5.训练 6.测试-分析-混淆矩阵等等&#xff0c;测试图片效果等 7.导出onnx 8.onnx推理 9.docker环境简单补充 1.前言 好久没有做图像分类了&#xff0c;于是想用商汤的mmclassification快速搞一波&#xff0c;发现已…

文心一言 VS 讯飞星火 VS chatgpt (380)-- 算法导论24.4 12题

十二、给出一个有效算法来解决 A x ⩽ b Ax⩽b Ax⩽b 的差分约束系统&#xff0c;这里 b b b 的所有元素为实数&#xff0c;而变量 x i x_i xi​ 中某个给定的子集是整数。如果要写代码&#xff0c;请用go语言。 文心一言&#xff1a; 差分约束系统问题通常用于解决带有约…

CSS网格布局

前言 希望元素按照网格的方式进行布局&#xff0c;最简单的方式就是利用网格布局&#xff0c;如图所示&#xff1a; 网格布局 设置网格布局的核心属性&#xff1a; ① display: grid 设置容器为网格布局容器&#xff08;如果希望设置行内的网格容器&#xff0c;可以设置disp…

QT访问数据库:应用提示Driver not loaded

在QT中运行完全正确错误截图 解决办法1 我用的是MySQL。我把libmysql.dll复制到应用程序的目录下&#xff0c;即可正常访问数据库。 解决办法2 bool open_work_db() {QString info "support drivers:";for (int i0; i<QSqlDatabase::drivers().size(); i){inf…

Rust 力扣 - 1. 两数相加

文章目录 题目描述题解思路题解代码题目链接 题目描述 题解思路 我们使用一个全局的备忘录&#xff0c;然后我们遍历数组&#xff0c;如果当前元素在备忘录里面找到了&#xff0c;就返回备忘录里面记录的下标和当前下标记录&#xff0c;没找到就把当前元素匹配的元素和当前元素…

十六:Python学习笔记-- 爬虫(2)requests 模块详解

目录 安装 requests 模块 基本请求方法 GET 请求 POST 请求 PUT 请求 DELETE 请求 添加请求头&#xff1a; 处理查询参数&#xff1a; 文件上传&#xff1a; 常见响应状态码 访问超时 cookie的查询和设置 查询 Cookies 设置 Cookies 设置爬虫代理 小试牛刀 安装 …

1Panel应用商店开源软件累计下载突破200万次!

2024年10月23日&#xff0c;1Panel应用商店内开源软件累计下载突破200万次。 1Panel&#xff08;github.com/1Panel-dev/1Panel&#xff09;是一款现代化、开源的Linux服务器运维管理面板&#xff0c;它致力于通过开源的方式&#xff0c;帮助用户简化建站与运维管理流程。 为…

C语言 | Leetcode C语言题解之第517题超级洗衣机

题目&#xff1a; 题解&#xff1a; int findMinMoves(int* machines, int machinesSize){int sum0;for(int i0;i<machinesSize;i){summachines[i];}if(sum%machinesSize!0){return -1;}int psum/machinesSize;int ans0;int cur0;for(int i0;i<machinesSize;i){cur(mac…

JavaSE笔记3】面向对象高级

目录 拓1&#xff1a;私有方法的优点 拓2&#xff1a;静态方法的优点 拓3&#xff1a;类的五大成分 拓4&#xff1a;硬编码和软编码 一、static 1. 概念 2. 成员变量在内存中执行原理 3. 类变量(静态变量)的使用场景 4. 两种成员变量 5. 两种成员方法 6. 类方法的使用场景 7.…

动态规划 —— 路径问题-礼物的最大价值

1. 剑指offer-JZ47-路径问题-礼物的最大价值 题目链接&#xff1a; 礼物的最大价值_牛客题霸_牛客网https://www.nowcoder.com/practice/2237b401eb9347d282310fc1c3adb134?tpId265&tqId39288&ru/exam/oj 2. 算法原理 状态表示&#xff1a;以莫一个位置位置为结尾 d…

Unity自定义数组在Inspector窗口的显示方式

了解 单行高度:EditorGUIUtility.singleLineHeight获取 PropertyField 控件所需的高度:EditorGUI.GetPropertyHeight属性是否在Inspector窗口展开&#xff1a;SerializedProperty.isExpanded可重新排序列表类&#xff1a;ReorderableList绘制纯色矩形&#xff1a;EditorGUI.Dr…

聊聊Web3D 发展趋势

随着 Web 技术的不断演进&#xff0c;Web3D 正逐渐成为各行业数字化的重要方向。Web3D 是指在网页中展示 3D 内容的技术集合。近年来&#xff0c;由于 WebGL、WebGPU 等技术的发展&#xff0c;3D 内容已经能够直接在浏览器中渲染&#xff0c;为用户提供更加沉浸、互动的体验。以…

【AIGC】ChatGPT应用之道:如何打破『专家幻象』,提升AI协作质量

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AIGC | ChatGPT 文章目录 &#x1f4af;前言&#x1f4af;ChatGPT的实际能力用户对ChatGPT的常见误解超越误解&#xff0c;合理设定期望总结 &#x1f4af;超越“专家”幻想设定合理的期望总结 &#x1f4af;提升人工智能协作质量…

Web3的去中心化社交网络:区块链技术如何改变互动方式

随着互联网技术的不断进步&#xff0c;社交网络正在经历一场深刻的变革。Web3&#xff0c;作为新一代互联网技术的代表&#xff0c;正通过区块链和去中心化理念改变着我们与他人互动的方式。传统的社交网络通常由大型公司控制&#xff0c;用户数据的集中化管理和隐私问题备受关…