新闻中心

React useRef 中数组操作:正确过滤与更新实践

2025-10-27
浏览次数:
返回列表

react useref 中数组操作:正确过滤与更新实践

在使用 React `useRef` 管理非渲染数据时,对其中存储的数组进行过滤或修改需要特别注意。本文将深入探讨 `Array.prototype.filter()` 等方法返回新数组的特性,以及如何正确地将过滤后的新数组重新赋值给 `useRef` 的 `current` 属性,确保数据状态的有效更新。同时,也将指出在访问 `useRef` 中数组长度时常见的错误,并提供正确的访问方式。

在 React 应用开发中,useRef 是一个非常有用的 Hook,它允许我们在组件的整个生命周期中存储和访问可变值,而不会触发组件重新渲染。这对于管理 DOM 元素、存储定时器 ID 或像本例中存储不需要触发 UI 更新的数组数据非常适用。然而,当对 useRef 中存储的数组进行操作时,如果不理解 J*aScript 数组方法的行为特性,很容易遇到数据更新无效的问题。

理解 Array.prototype.filter() 的工作原理

Array.prototype.filter() 是一个非破坏性方法,这意味着它不会修改原始数组。相反,它会遍历数组中的每个元素,并根据提供的回调函数返回一个新数组,其中包含所有通过测试的元素。

考虑以下代码片段,这是在 useRef 中尝试过滤数组时常见的问题:

// 假设 items.current 是一个数组,例如:[{ name: 'toy1' }, { name: 'toy2' }]
// 尝试过滤掉名为 'toy' 的对象
items.current.filter((item) => item.name !== toy);
// 此时,items.current 仍然是原始数组,没有任何改变

这里的 filter 方法确实返回了一个新数组,其中不包含 name 等于 toy 的元素。但是,这个新数组并没有被赋值给任何变量,更没有被重新赋值给 items.current。因此,items.current 仍然指向原始的、未被过滤的数组。

正确更新 useRef 中存储的数组

要正确地更新 useRef 中存储的数组,我们需要将 filter 方法返回的新数组显式地赋值回 ref.current 属性。

// 假设 items 是一个 useRef 实例
// 正确地过滤并更新 items.current
items.current = items.current.filter((item) => item.name !== toy);
// 现在,items.current 已经更新为过滤后的新数组

通过这种方式,我们确保了 items.current 始终指向最新的、经过过滤的数组状态。

小爱开放平台 小爱开放平台

小米旗下小爱开放平台

小爱开放平台 291 查看详情 小爱开放平台

正确访问 useRef 中数组的长度

另一个常见的错误是,当 items 是一个 useRef 实例时,错误地尝试访问 items.length。useRef 返回的对象本身并没有 length 属性。数组数据实际存储在 items.current 中。

// 错误示例:试图访问 useRef 对象的 length 属性
if (items.length === 0) {
  // 这将永远不会为 true,因为 items 是一个 { current: [...] } 对象
  console.log('Winner');
}

// 正确示例:访问 useRef.current 中数组的 length 属性
if (items.current.length === 0) {
  console.log('Winner');
  // 导航到排行榜页面
  n*igate("/leaderboard", { state: time });
}

始终记住,要访问 useRef 存储的实际值,必须通过其 current 属性。

综合示例:隐藏物品游戏中的应用

结合上述修正,以下是隐藏物品游戏 handleAction 函数的正确实现:

import { useN*igate } from 'react-router-dom';
import { useState, useEffect, useRef } from "react";
import supabase from "../config/supabaseClient";
import Image from "./image";
import Timer from "./timer";

const Game = () => {
  let items = useRef([]); // 使用 useRef 存储物品列表
  const [fetchError, setFetchError] = useState(null);
  const [found, setFound] = useState("");
  const [time, setTime] = useState(0);
  const n*igate = useN*igate();

  useEffect(() => {
    const fetchOptions = async () => {
      const { data, error } = await supabase
        .from('items')
        .select();

      if (error) {
        setFetchError('Could not fetch items');
        items.current = [];
      }

      if (data) {
        items.current = data; // 初始化 useRef 中的数组
        setFetchError(null);
      }
    }
    fetchOptions();
  }, []);

  function handleAction(click, toy) {
    const item = items.current.find(item => item.name === toy);

    if (!item) {
      setFound(`Not quite, try again!`);
      return;
    }

    if (click.x > item.left && click.x < item.right) {
      if (click.y < item.bottom && click.y > item.top) {
        setFound(`Well done! You've found Sarah's ${toy}`);
        // 关键修正:重新赋值过滤后的数组
        items.current = items.current.filter((i) => i.name !== toy);
        console.log(items.current);

        // 关键修正:正确检查数组长度
        if (items.current.length === 0) {
          console.log('Winner');
          n*igate("/leaderboard", { state: time });
        }
      }
    } else {
      setFound(`Not quite, try again!`);
      return;
    }
  }

  return (
    <>
      {fetchError && (<p>{fetchError}</p>)}
      <Timer time={time} setTime={setTime} />
      <Image handleAction={handleAction} />
      <p>{found}</p>
    </>
  );
}

export default Game;

注意事项与总结

  1. 数组方法的非破坏性: 记住 filter(), map(), slice() 等方法返回新数组,而不会修改原始数组。如果需要修改原始数组,可以考虑使用 splice() (但它会改变原数组,与 React 的不可变性原则不太符,除非你明确知道自己在做什么) 或者直接重新赋值。
  2. useRef.current 的重要性: 始终通过 ref.current 访问或修改 useRef 存储的值。useRef 本身是一个对象,current 属性才是真正存储你数据的容器。
  3. useRef 与 useState 的选择: 如果数据的改变需要触发组件重新渲染,那么应该使用 useState。如果数据是可变的,但其改变不需要触发重新渲染(例如本例中隐藏的物品列表),那么 useRef 是一个更合适的选择。

通过理解这些核心概念,你可以更有效地在 React 应用中利用 useRef 处理复杂的数据结构,避免常见的陷阱,并编写出更健壮、更专业的代码。

以上就是React useRef 中数组操作:正确过滤与更新实践的详细内容,更多请关注其它相关文章!


# 自定义  # seo文章发布视频教程  # 日照建设网站的公司  # 如何去seo网站排名  # 五一创意营销推广方案  # 工装企业网站推广  # 永城网站推广设计公司  # 三明网站推广威莘hfqjwl下拉  # 乐视网站外推广  # seo首页优化推荐22火星  # 酒类可以推广营销吗  # 如何实现  # 服务端  # 它会  # react  # 不需要  # 正确地  # 数据结构  # 小爱  # 回调  # 是一个  # gate  # 应用开发  # win  # ai  # 回调函数  # java  # javascript 


相关栏目: 【 科技资讯46185 】 【 网络学院92790


相关推荐: Log4j Console Appender性能瓶颈与高并发优化策略  支付宝解绑银行卡步骤_支付宝如何解除绑定银行卡  如何为你的Composer包编写自动化测试_集成PHPUnit到Composer的scripts工作流  Lar*el 8 多关键词数据库搜索优化实践  MAC的“快捷指令”怎么同步到iPhone_MAC利用iCloud同步所有设备的自动化指令  单射、满射与双射的关系 一文理清所有逻辑  sublime怎么覆盖插件的默认快捷键_sublime快捷键优先级与设置  漫蛙Manwa2官网入口地址分享 漫蛙漫画PC版永久访问通道  “在文档元素之后找到了标记”是什么错误? 检查并修复XML中多个根元素的3个方法  顺丰快递查询系统 官方正版查询入口  J*aScript动态修改指定div内所有a标签样式指南  Django表单验证失败时保留用户输入数据的最佳实践  ACG动漫手机版官网入口 手机ACG动漫APP在线观看正版  “音游” × “怪文书” 题材的节奏冒险游戏 《晕晕电波症候群》确定于2026年4月发售!  J*aScript数组对象转换:按指定键分组与值收集  我的世界mc.js免费游戏直接能玩 我的世界mc.js小游戏免费秒玩入口  Sublime Text怎么设置垂直标尺_Sublime配置Rulers规范代码长度  深入理解J*a链表中的IPosition接口与使用  谷歌浏览器最新官方入口链接 谷歌浏览器网页版官网导航  css绝对定位元素脱离父容器怎么办_确保父元素position非static  mysql备份恢复性能优化_mysql备份恢复性能优化方法  excel怎么制作工资条 excel快速生成工资条的方法  快手极速版在线观看 官方网页版登录地址  J*a TimerTask文件监控:HashMap状态管理与常见陷阱规避指南  QQ邮箱登录官网首页 腾讯QQ邮箱网页入口  解决Rails应用中内容错位与Turbo警告:meta标签误用导致富文本渲染异常  Bilibili动漫最新防封地址发布-Bilibili动漫2025年最稳正版入口推荐  如何将一个大型PHP应用拆分为多个Composer包_微服务与模块化架构的Composer实践  知音漫客官网漫画下载_知音漫客网页版阅读记录  黑猫投诉统一入口官网 消费者权益保护投诉平台  使用 Pandas 高效处理 .dat 文件:数据清洗与数值计算实战  outlook中文官网入口地址 outlook官方中文版直达首页链接  Fabric模组开发:自定义物品与物品组的现代管理方法  单12V-2&#215;6实现为RTX 5090供电750W!甚至都没敢跑分  解决Bootstrap卡片顶部边距导致背景图下移的问题  C++如何连接MySQL数据库_C++使用Connector/C++操作MySQL数据库教程  age动漫网站入口 age动漫官网直接访问入口  J*a 递归快速排序中静态变量的状态管理与陷阱  黑鲨3Pro怎样在相册开漫画风滤镜_iPhone黑鲨3Pro相册开漫画风滤镜【趣味滤镜】  电脑安装程序提示“错误1722”怎么办_Windows Installer服务问题解决【教程】  漫画星球免费下拉式入口 漫画星球免费漫画在线阅读网站  Python中如何避免重复条件判断:利用数据结构实现动态逻辑  Excel Power Pivot如何处理XML数据源 构建高级数据模型  格力空气能E5故障代码是什么情况_格力空气能E5代码解析与应对措施  谷歌邮箱注册显示错误Gmail服务器异常与延迟处理  Golang如何使用net/url解析URL_Golang URL解析与处理方法  TikTok搜索结果不显示如何解决 TikTok搜索刷新优化方法  Win11怎么隐藏桌面图标 Win11一键隐藏所有桌面元素及恢复显示  Win10如何清理注册表垃圾 Win10手动清理无效注册表【技巧】  Python自定义类排序:解决lambda键值访问TypeError的实践指南 

搜索