0

0

React中useRef管理数组的正确过滤与长度判断

霞舞

霞舞

发布时间:2025-10-27 11:04:01

|

1011人浏览过

|

来源于php中文网

原创

react中useref管理数组的正确过滤与长度判断

本文旨在解决在React应用中使用`useRef`管理数组时,进行过滤操作不生效以及判断数组长度错误的问题。核心在于理解`Array.prototype.filter()`方法返回新数组的特性,以及`useRef`对象如何正确访问其内部可变值。通过本文,你将学会如何正确地过滤并更新`ref.current`中的数组,并准确获取其长度。

在React开发中,useRef是一个强大的Hook,常用于在组件的整个生命周期中存储可变值,而这些值的变化不会触发组件重新渲染。这对于管理DOM元素引用、计时器ID或在多次渲染之间需要持久化的非UI数据(如游戏中的隐藏物品列表)非常有用。然而,在使用useRef管理数组时,开发者常会遇到两个常见误区:错误地过滤数组和错误地获取数组长度。

理解Array.prototype.filter()的特性

Array.prototype.filter()方法是JavaScript中一个常用的数组操作方法。它的核心特性是非破坏性,即它不会修改原始数组。相反,它会创建一个新数组,其中包含通过指定回调函数测试的所有元素。

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

items.current.filter((item) => item.name !== toy);

这段代码的问题在于,filter()方法执行后会返回一个新数组,但这个新数组并没有被赋值回items.current。因此,items.current仍然指向原始的、未经过滤的数组,导致过滤操作看似“没有效果”。

正确过滤并更新useRef中的数组

要正确地过滤useRef中存储的数组,你需要将filter()方法返回的新数组显式地赋值回ref.current。这样才能确保ref中存储的值得到更新。

// 假设 items 是一个通过 useRef([]) 初始化的 ref
// item.name !== toy 是你的过滤条件
items.current = items.current.filter((item) => item.name !== toy);

通过这种方式,items.current现在指向的是经过滤的新数组,从而实现了对数组的有效修改。

正确获取useRef中数组的长度

另一个常见错误是尝试直接通过ref对象本身获取数组长度,例如items.length。useRef返回的是一个包含current属性的普通JavaScript对象,而你实际存储的数组是该current属性的值。

// 错误示例:试图直接访问 ref 对象的 length 属性
if (items.length === 0) {
  console.log('Winner');
  // ...
}

items对象本身并没有length属性(除非你手动添加),其length属性将是undefined,或者在某些情况下,如果items被意外地赋值为数组,则可能得到错误的结果。

PageGen
PageGen

AI页面生成器,支持通过文本、图像、文件和URL一键生成网页。

下载

要正确获取存储在useRef中的数组的长度,你必须通过current属性来访问它:

// 正确示例:通过 items.current 访问数组的 length 属性
if (items.current.length === 0) {
  console.log('Winner');
  navigate("/leaderboard", { state: time });
}

这确保你是在对实际的数组进行操作,而不是对useRef对象本身。

综合示例与注意事项

将上述修正应用到原始代码中,handleAction函数应修改如下:

import { useNavigate } 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 navigate = useNavigate();

  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; // 将数据赋值给 ref.current
        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 = items.current.filter((i) => i.name !== toy);
        console.log("Updated items in ref:", items.current);

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

  return (
    <>
      {fetchError && (

{fetchError}

)}

{found}

); } export default Game;

关键注意事项:

  1. useRef与useState的选择: 当你存储的数据需要触发组件重新渲染时,应使用useState。如果数据仅用于在组件实例的生命周期内持久化,且其变化不应直接导致UI更新,那么useRef是更合适的选择。在这个隐藏对象游戏的例子中,items数组的过滤不需要立即触发UI重新渲染(因为对象是“隐藏的”),所以useRef是合理的。
  2. filter()的纯粹性: 始终记住filter()、map()、slice()等数组方法返回新数组。如果你想修改原数组,可以考虑使用splice()(它会修改原数组)或重新赋值。
  3. ref.current的访问: 任何时候需要读取或修改useRef存储的值,都必须通过ref.current属性。

总结

正确使用useRef管理可变数据,特别是数组,需要对JavaScript数组方法的特性以及React useRef的工作原理有清晰的理解。核心要点是:Array.prototype.filter()方法返回一个新数组,因此必须将这个新数组重新赋值给ref.current才能更新ref中存储的数据;同时,访问useRef中存储的数组的任何属性(如length)都必须通过ref.current。掌握这些原则将帮助你更有效地利用useRef来管理组件内部的非渲染状态。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
length函数用法
length函数用法

length函数用于返回指定字符串的字符数或字节数。可以用于计算字符串的长度,以便在查询和处理字符串数据时进行操作和判断。 需要注意的是length函数计算的是字符串的字符数,而不是字节数。对于多字节字符集,一个字符可能由多个字节组成。因此,length函数在计算字符串长度时会将多字节字符作为一个字符来计算。更多关于length函数的用法,大家可以阅读本专题下面的文章。

924

2023.09.19

golang map内存释放
golang map内存释放

本专题整合了golang map内存相关教程,阅读专题下面的文章了解更多相关内容。

75

2025.09.05

golang map相关教程
golang map相关教程

本专题整合了golang map相关教程,阅读专题下面的文章了解更多详细内容。

36

2025.11.16

golang map原理
golang map原理

本专题整合了golang map相关内容,阅读专题下面的文章了解更多详细内容。

60

2025.11.17

java判断map相关教程
java判断map相关教程

本专题整合了java判断map相关教程,阅读专题下面的文章了解更多详细内容。

40

2025.11.27

undefined是什么
undefined是什么

undefined是代表一个值或变量不存在或未定义的状态。它可以作为默认值来判断一个变量是否已经被赋值,也可以用于设置默认参数值。尽管在不同的编程语言中,undefined可能具有不同的含义和用法,但理解undefined的概念可以帮助我们更好地理解和编写程序。本专题为大家提供undefined相关的各种文章、以及下载和课程。

5364

2023.07.31

网页undefined是什么意思
网页undefined是什么意思

网页undefined是指页面出现了未知错误的意思,提示undefined一般是在开发网站的时候定义不正确或是转换不正确,或是找不到定义才会提示undefined未定义这个错误。想了解更多的相关内容,可以阅读本专题下面的文章。

3083

2024.08.14

网页undefined啥意思
网页undefined啥意思

本专题整合了undefined相关内容,阅读下面的文章了解更多详细内容。后续继续更新。

526

2025.12.25

俄罗斯Yandex引擎入口
俄罗斯Yandex引擎入口

2026年俄罗斯Yandex搜索引擎最新入口汇总,涵盖免登录、多语言支持、无广告视频播放及本地化服务等核心功能。阅读专题下面的文章了解更多详细内容。

84

2026.01.28

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
React 教程
React 教程

共58课时 | 4.2万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

React核心原理新老生命周期精讲
React核心原理新老生命周期精讲

共12课时 | 1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号