React进阶 - 15(React 中 ref 的使用)

news2024/11/23 12:46:06

本章内容

目录

    • 一、e.target 获取事件对应“元素”的DOM节点
    • 二、ref
    • 三、ref 和 setState 合用

上一节我们了解了 React中的”虚拟DOM“中的”Diff算法““ ,本节我们来说一说 Reactref的使用

一、e.target 获取事件对应“元素”的DOM节点

  • 打开之前工程中的 TodoList.js代码
  • 需求:当 input框中的数据变化时,要求拿到这个input框节点 DOM
  • 这个需求我们可以使用最原始的 e.target来实现
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";

class TodoList extends Component{
  constructor(props) {
    super(props)
    this.deleteData = this.deleteData.bind(this)
    this.addListData = this.addListData.bind(this)
    this.changeInputValue = this.changeInputValue.bind(this)
    this.state = {
      inputValue: '', 
      list: []
    } 
  }

  render() {  
    console.log('render 函数执行了')
    return (
      <Fragment>
        <div>
          <input value={this.state.inputValue} onChange={this.changeInputValue} />
          <button onClick={this.addListData}> 提交 </button>
        </div>

        <ul> {this.getTodoItem()} </ul>
      </Fragment>
    )
  }

  getTodoItem() {
    return this.state.list.map((item, index) => {
      return <TodoItem key={index} content={item} index={index} deleteFn={this.deleteData}></TodoItem>
    })
  }

  deleteData(index) {
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
      return {list}
    })

  }

  addListData() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: ''
    }))
  }

  // 1、当input框里的值发生变化后,该函数会执行
  changeInputValue(e) {
  // 2、我们试着在控制台打印出 e.target,观察其内容
   console.log(e.target)
  // 3、拿到输入框的数据
    const value = e.target.value
  // 4、更新inputValue 数据
    this.setState(() => ({inputValue: value})) 
  }
}

export default TodoList
  • 运行代码,打开浏览器的控制台,可以看到,每当输入框的数据变化,就会打印出 input框的 DOM节点
    在这里插入图片描述

  • 从上面的演示可以看出,在 React中,仍然可以使用 e.target获取事件对应“元素”的DOM节点

二、ref

  • refreference的简写,其含义为“引用”
  • React中,我们可以使用 ref来获取 DOM元素。但是一般情况下,我们尽量不要去使用 ref,但有时一些复杂的业务(如:动画),其不可避免的还是会用到页面上的一些 DOM标签。
  • 我们使用 ref来实现上面的需求:“当 input框中的数据变化时,要求拿到这个input框节点 DOM
import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";

class TodoList extends Component{
  constructor(props) {
    super(props)
    this.deleteData = this.deleteData.bind(this)
    this.addListData = this.addListData.bind(this)
    this.changeInputValue = this.changeInputValue.bind(this)
    this.state = {
      inputValue: '', 
      list: []
    } 
  }

  render() {  
    return (
      <Fragment>
        <div>
          {/* 
           1、首先给 input 元素添加一个 ref 属性,它等于一个”箭头函数”。
           ”箭头函数“自动收到一个参数,名字可以任意取

           2、箭头函数使用一个固定的写法 this.input=input,表示,
           我构建了一个“引用”ref,这个“引用”叫做 this.input,
           它指向 input框对应的 DOM 节点

           3、接着我们使用 ref 方式获得的 DOM 节点来替换 changeInputValue 方法里的 e.target.value 写法

          */}
          <input value={this.state.inputValue} onChange={this.changeInputValue} ref={(input) => this.input = input} />
          <button onClick={this.addListData}> 提交 </button>
        </div>

        <ul> {this.getTodoItem()} </ul>
      </Fragment>
    )
  }

  getTodoItem() {
    return this.state.list.map((item, index) => {
      return <TodoItem key={index} content={item} index={index} deleteFn={this.deleteData}></TodoItem>
    })
  }

  deleteData(index) {
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
      return {list}
    })

  }

  addListData() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: ''
    }))
  }

  // 4、去掉入参 e, 使用 ref 方式获得的 DOM 节点来替换 e.target.value 写法
  changeInputValue() {
    console.log(this.input)
    const value = this.input.value
    this.setState(() => ({inputValue: value})) 
  }
}

export default TodoList
  • 运行代码,打开浏览器的控制台,可以看到效果正常运行,无报错。所以说 ref用于获取 DOM节点是可以被正常使用的。但,注意不要滥用,React是“数据驱动”的框架,非特殊情况,不要主动去操作 DOM,而且,用 ref时,一不小心就会有bug,比如和 setState合用
    在这里插入图片描述

三、ref 和 setState 合用

  • 上面我们提到 refsetState合用时,有的时候会有bug。现在我们用一个例子来说明

  • 需求是这样的:当输入框输入内容并点击“提交”,要求打印出 list数据的 DOM节点内容以及长度(即:打印 ul元素节点,以及ul中的div长度)

  • 要实现上面的需求,思路大概是

1、给 ul 绑定 ref 属性,获取到 DOM 节点

2、在“提交”按钮点击事件 “addListData” 中打印 ul 节点,并使用原生的 querySelectorAll 方法 打印 ul 中 div 的长度

import React, { Component, Fragment } from "react";
import TodoItem from "./TodoItem";

class TodoList extends Component{
  constructor(props) {
    super(props)
    this.deleteData = this.deleteData.bind(this)
    this.addListData = this.addListData.bind(this)
    this.changeInputValue = this.changeInputValue.bind(this)
    this.state = {
      inputValue: '', 
      list: []
    } 
  }

  render() {  
    return (
      <Fragment>
        <div>
          <input value={this.state.inputValue} onChange={this.changeInputValue} ref={(input) => this.input = input} />
          <button onClick={this.addListData}> 提交 </button>
        </div>

        {/* 1、给 ul 绑定 ref 属性,获取到 DOM 节点  */}
        <ul ref={(ul) => this.ul = ul }> {this.getTodoItem()} </ul>
      </Fragment>
    )
  }

  getTodoItem() {
    return this.state.list.map((item, index) => {
      return <TodoItem key={index} content={item} index={index} deleteFn={this.deleteData}></TodoItem>
    })
  }

  deleteData(index) {
    this.setState((prevState) => {
      const list = [...prevState.list]
      list.splice(index, 1)
      return {list}
    })

  }

  // 2、在“提交”按钮点击事件 “addListData” 中打印 ul 节点
  // 并使用原生的 querySelectorAll 方法 打印 ul 中 div 的长度
  addListData() {
    console.log(this.ul) // 打印 ul 节点
    console.log(this.ul.querySelectorAll("div").length) // 使用原生的 querySelectorAll 方法 打印 ul 中 div 的长度

    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: ''
    }))
  }

  changeInputValue() {
    const value = this.input.value
    this.setState(() => ({inputValue: value})) 
  }
}

export default TodoList
  • 运行代码,回到页面控制台查看 this.ul.querySelectorAll("div").length打印出的 div长度,发现输出的长度跟真实的长度不对等,输出长度比实际长度少1个!!!
    在这里插入图片描述

  • 为什么会出现这个问题呢?

答:React 中 setState 被设计成异步的,当数据变化时, setState 中的函数体并不会立即执行,它要等一会儿。

而 console.log(this.ul.querySelectorAll("div").length) 从页面效果来看是在 setState 底层运行之前执行了
  • 怎么解决这个问题呢?很简单,setState里面有第二个参数(也是一个函数),我们可以在这个函数里执行 console.log(this.ul.querySelectorAll("div").length)
  // 2、在“提交”按钮点击事件 “addListData” 中打印 ul 节点
  // 并使用原生的 querySelectorAll 方法 打印 ul 中 div 的长度
  addListData() {
    this.setState((prevState) => ({
      list: [...prevState.list, prevState.inputValue],
      inputValue: ''
    }), () => {
      console.log(this.ul) // 打印 ul 节点
      console.log(this.ul.querySelectorAll("div").length) // 使用原生的 querySelectorAll 方法 打印 ul 中 div 的长度
    })
  }
  • 再次运行代码,发现这个问题就解决了~
    在这里插入图片描述

到此,本章内容结束!

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

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

相关文章

elasticsearch重置密码操作

安装es的时候需要测试这个url&#xff1a;http://127.0.0.1:9200/ 出现弹窗让我输入账号和密码。我第一次登录&#xff0c;没有设置过账号和密码&#xff0c; 解决方法是&#xff1a;在es的bin目录下打开cmd窗口&#xff0c;敲命令&#xff1a;.\elasticsearch-reset-password…

给mysql设置时区

每次重启MySQL服务器后&#xff0c;使用IDEA的database navigator连接都会出现这种情况 解决方式就是 命令行登录后 set global time_zone 8:00;嘿嘿把之前自家简书文章 给mysql设置时区 搬运过来了&#xff0c;方便查阅

Zookeeper相关面试准备问题

Zookeeper介绍 Zookeeper从设计模式角度来理解&#xff0c;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它负责存储和管理大家都关心的数据&#xff0c;然后接受观察者的注册&#xff0c;一旦这些数据的状态发生了变化&#xff0c;Zookeeper就负责通知已经在Zoo…

【lesson37】自己设计用户级缓冲区

文章目录 自己设计用户级缓冲区简易MyFILE_的结构fopen_的实现fputs_的实现fclose_的实现fflush_的实现 完整版代码 自己设计用户级缓冲区 因为用户缓冲区在FILE中&#xff0c;所以我们直接模仿C语言提供的文件操作接口&#xff0c;顺便实现缓冲区。 使用文件系统的框架&#…

C++ 图(三十八)【第四篇】

接下来&#xff0c;我们先学习一个概念&#xff0c;带有权值的图&#xff0c;其实就是每条边上有一个自己独立的值了&#xff0c;接下来我们来进行一个深入的了解吧。 1.带权值得的图的概念 在前面的课程中&#xff0c;图中的边都只是用来表示两个点之间是否存在关系&#xff…

SQL注入其他方法

此次实验因为环境问题很多无法复现&#xff0c;在此只讨论过程和方法 一、SQL注入之outfile注入 mysql的outfile的作用是导出文件&#xff0c;使用此方法的必要条件&#xff1a;&#xff08;此方法成功率极低&#xff09; 1、知道目标网站的物理路径&#xff1b; 2、%secur…

Python算法题集_螺旋矩阵

Python算法题集_螺旋矩阵 题目54&#xff1a;螺旋矩阵1. 示例说明2. 题目解析- 题意分解- 优化思路- 测量工具 3. 代码展开1) 标准求解【检测4个方向】2) 改进版一【检测2个方向】3) 改进版二【可读性改进】 4. 最优算法 题目54&#xff1a;螺旋矩阵 本文为Python算法题集之一…

《Pandas 简易速速上手小册》第9章:Pandas 数据可视化(2024 最新版)

文章目录 9.1 Pandas 内置可视化工具9.1.1 基础知识9.1.2 重点案例&#xff1a;销售数据分析9.1.3 拓展案例一&#xff1a;产品评价统计9.1.4 拓展案例二&#xff1a;员工满意度分布 9.2 与 Matplotlib 和 Seaborn 集成9.2.1 基础知识9.2.2 重点案例&#xff1a;销售趋势分析9.…

「递归算法」:验证二叉搜索树

一、题目 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。节点的右子树只包含 大于 当前节点的数。所有左子树和右子树自身必须也是二叉搜索树。 示例 1&#xff…

vulhub中Apache APISIX 默认密钥漏洞复现(CVE-2020-13945)

Apache APISIX是一个高性能API网关。在用户未指定管理员Token或使用了默认配置文件的情况下&#xff0c;Apache APISIX将使用默认的管理员Token edd1c9f034335f136f87ad84b625c8f1&#xff0c;攻击者利用这个Token可以访问到管理员接口&#xff0c;进而通过script参数来插入任意…

110.乐理基础-五线谱-五线谱的速度

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;五线谱的附点、休止符、连线、延音线-CSDN博客 上一个内容里练习的答案&#xff1a; 五线谱里的情绪与速度也是跟简谱里一样&#xff0c;详情看&#xff1a;音乐的速度 专栏里的内容&#xff0c;根据创建时间&…

CNN应用Keras Tuner寻找最佳Hidden Layers层数和神经元数量

介绍&#xff1a; Keras Tuner是一种用于优化Keras模型超参数的开源Python库。它允许您通过自动化搜索算法来寻找最佳的超参数组合&#xff0c;以提高模型的性能。Keras Tuner提供了一系列内置的超参数搜索算法&#xff0c;如随机搜索、网格搜索、贝叶斯优化等。它还支持自定义…

《Python 网络爬虫简易速速上手小册》第2章:网络爬虫准备工作(2024 最新版)

文章目录 2.1 选择合适的爬虫工具和库2.1.1 重点基础知识讲解2.1.2 重点案例&#xff1a;使用 Scrapy 抓取电商网站2.1.3 拓展案例 1&#xff1a;使用 Requests 和 BeautifulSoup 抓取博客文章2.1.4 拓展案例 2&#xff1a;使用 Selenium 抓取动态内容 2.2 设置开发环境2.2.1 重…

计算机毕业设计 | vue+SpringBoot图书借阅管理系统(附源码)

1&#xff0c; 概述 1.1 课题背景 随着现在科学技术的进步&#xff0c;人类社会正逐渐走向信息化&#xff0c;图书馆拥有丰富的文献信息资源&#xff0c;是社会系统的重要组成部分&#xff0c;在信息社会中作用越来越重要&#xff0c;在我国图书馆计算机等 信息技术的应用起步…

【Linux】文件重定向与实现支持文件重定向的minishell

目录 0.前提 ​编辑 1.重定向 1.1重定向的本质 1.2dup2 1.3模拟实现输出重定向 > 1.4模拟实现追加重定向 >> 1.5模拟实现输入重定向 < 2.让minishell支持重定向 0.前提 文件描述符的分配规则&#xff1a; 在文件描述符表里面&#xff0c;从小到大按照顺…

linux中的mtime,ctime,atime

目录 结论 文件 touch新文件 调整文件内容 echo直接修改 vi修改 修改文件属性 调整归属 调整权限 读取文件 目录 增加文件 调整目录下文件属性 访问目录下文件 删除文件 结论 mtime&#xff1a;文件内容的修改时间&#xff08;不含权限、属组修改&#xff09; …

计算机网络-封装成帧透明传输(组帧方法)

文章目录 数据链路层功能概述封装成帧透明传输组帧方法字符计数法字符填充法零比特填充法违规编码法 字符填充法为啥复杂和不兼容 数据链路层功能概述 类似老板让小秘书送文件给别的公司&#xff0c;小秘书告诉傻子怎么把该文件送到别的公司的小秘书&#xff0c;然后别的公司的…

基于springboot就业信息管理系统源码和论文

随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;就业信息管理系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;人工管理显然已无法应对时代的变化&#xff0c;而…

挑战杯 python 机器视觉 车牌识别 - opencv 深度学习 机器学习

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于python 机器视觉 的车牌识别系统 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;3分工作量&#xff1a;3分创新点&#xff1a;3分 &#x1f9ff; 更多资…

【王者荣耀】:背后的技术之谜,揭秘游戏背后的实现奥秘!

目录 1、引言 2、游戏引擎 3、网络技术 4、图形渲染 5、操作控制 6、AI算法 7、数据管理 8、安全防护 9、优化与性能 10、未来发展 11、结语 1、引言 随着智能手机的普及和移动互联网的发展&#xff0c;手机游戏已经成为人们日常娱乐的重要组成部分。而在众多手机游…