React Native 中的 useRef 介绍

在 React Native 中,useRef 是 React 提供的一个非常有用的 Hook,它的作用是在函数组件中保持对某些数据或是组件的持久引用。并且它的改变不会触发组件重新渲染。 在之前的类组件开发模式下,我们通常会用 this 关键字来保存对组件或者数据的引用。而在函数组件中没有 this,这时,useRef 就应运而生了。

在这篇文章中,我会介绍 useRef 的使用方式、原理、常见场景,希望可以帮助到大家。

首先,我们来看一下 useRef 在代码中是如何使用的。

基本使用

ts 复制代码
// 声明一个属性
const refContainer = useRef(initialValue);
// 访问属性的值
console.log(refContainer.current);
// 修改属性的值
refContainer.current = 10;

可以看到,useRef 的使用分以下三步:

  • 第一步,声明并且赋值一个初始值;
  • 第二步,在对应逻辑中修改它的值。需要注意的是:我们需要修改 .current 而不是直接修改声明的变量;
  • 第三步,通过 refContainer.current 访问数据即可。

它的使用还是比较简单的。下面来一下具体的有哪些常用的使用场景。

useRef 使用场景举例

引用组件实例

在 React Native 的日常中,我们经常需要获取 TextInputScrollViewFlatList 等组件的实例来调用方法。

tsx 复制代码
import React, { useRef } from 'react';
import { View, TextInput, Button } from 'react-native';

export default function UseRefExample() {
  const inputRef = useRef<TextInput>(null);

  const focusInput = () => {
    inputRef.current?.focus(); // 调用 TextInput 的 focus 方法
  };

  return (
    <View>
      <TextInput ref={inputRef} placeholder="请输入内容" style={{ borderWidth: 1, padding: 8 }} />
      <Button title="聚焦输入框" onPress={focusInput} />
    </View>
  );
}

在这个例子中,我们通过 inputRef.current.focus() 可以让输入框获得焦点,而不需要重新渲染组件。

存储可变值

useRef 也可以用来存储组件生命周期中需要的可变值,例如定时器 ID、计数器等。

tsx 复制代码
import React, { useRef, useEffect, useState } from 'react';
import { View, Text, Button } from 'react-native';

export default function TimerExample() {
  const [count, setCount] = useState(0);
  const intervalRef = useRef<NodeJS.Timeout | null>(null);

  const startTimer = () => {
    if (!intervalRef.current) {
      intervalRef.current = setInterval(() => {
        setCount(prev => prev + 1);
      }, 1000);
    }
  };

  const stopTimer = () => {
    if (intervalRef.current) {
      clearInterval(intervalRef.current);
      intervalRef.current = null;
    }
  };

  useEffect(() => {
    return () => stopTimer(); // 组件卸载时清理定时器
  }, []);

  return (
    <View>
      <Text>计数: {count}</Text>
      <Button title="开始" onPress={startTimer} />
      <Button title="停止" onPress={stopTimer} />
    </View>
  );
}

这里的 intervalRef 不会触发组件重新渲染,它只是存储一个定时器 ID,以便后续清理。

与 useEffect 结合使用

当我们需要访问最新的状态或 props,但又不想在依赖数组中引发无限循环时,可以借助 useRef

tsx 复制代码
import React, { useEffect, useRef, useState } from 'react';
import { View, Button, Text } from 'react-native';

export default function LatestValueExample() {
  const [count, setCount] = useState(0);
  const latestCount = useRef(count);

  useEffect(() => {
    latestCount.current = count; // 同步最新值
  }, [count]);

  const showLatestCount = () => {
    setTimeout(() => {
      console.log('最新计数值:', latestCount.current);
    }, 3000);
  };

  return (
    <View>
      <Text>计数: {count}</Text>
      <Button title="增加" onPress={() => setCount(count + 1)} />
      <Button title="3秒后打印最新值" onPress={showLatestCount} />
    </View>
  );
}

在这个例子中,即使 setTimeout 在 3 秒后才执行,也能拿到最新的 count 值,而不需要在 useEffect 或依赖数组中做复杂处理。

如果 latestCount 没有使用 useRef ,而是普通的变量的话,那么每次组件重新渲染时,它的值会被重置。当你点击「增加」按钮,count 会更新,而 latestCount 并不会持久化。你预期在 3 秒后打印正确的 count 值,但是由于 latestCount 被重置,所以打印的始终是第一次渲染时的 count 值。

控制动画或滑动位置

在 React Native 中,useRef 对配合 Animated.Value 或 ScrollView 的 scrollTo 也非常有用。

tsx 复制代码
import React, { useRef } from 'react';
import { View, ScrollView, Button, Text, StyleSheet } from 'react-native';

export default function ScrollExample() {
  const scrollRef = useRef<ScrollView>(null);

  const scrollToBottom = () => {
    scrollRef.current?.scrollToEnd({ animated: true });
  };

  return (
    <View style={{ flex: 1 }}>
      <ScrollView ref={scrollRef} style={styles.scrollView}>
        {Array.from({ length: 50 }).map((_, index) => (
          <Text key={index}>第 {index + 1} 行</Text>
        ))}
      </ScrollView>
      <Button title="滚动到底部" onPress={scrollToBottom} />
    </View>
  );
}

const styles = StyleSheet.create({
  scrollView: { flex: 1, padding: 10 },
});

这里 scrollRef.current.scrollToEnd() 可以控制 ScrollView 滚动到最后。

总结

useRef 是 React Native 中非常实用的 Hook,既能替代类组件中的 this,又能在函数组件中保存可变数据,同时保持性能优势。useRef 常用于在函数组件中创建可变引用,并且这种引用的变化不会触发组件的重新渲染。它既可以用来引用组件实例,也能用来存储一些可变的值,例如定时器的 ID 或者最新的状态,非常适合在动画、ScrollView 控制、延迟获取最新状态等场景下使用。我们额外需要注意的是:useRef 并不能用来进行管理 UI 状态,否则可能会导致逻辑混乱。

相关推荐
小仙女喂得猪11 小时前
2025 Android原生开发者角度的React/ReactNative 笔记整理
react native·react.js
XTransfer技术12 小时前
RN也有微前端框架了? Xtransfer的RN优化实践(一)多bundle架构
前端·react native
光影少年12 小时前
webpack打包优化
webpack·掘金·金石计划·前端工程化
光影少年2 天前
Typescript工具类型
前端·typescript·掘金·金石计划
诚实可靠王大锤2 天前
react-native项目通过华为OBS预签名url实现前端直传
前端·react native·华为
三思而后行,慎承诺5 天前
Reactnative实现远程热更新的原理是什么
javascript·react native·react.js
木西7 天前
React Native DApp 开发全栈实战·从 0 到 1 系列(永续合约交易-前端部分)
react native·web3·智能合约
歪歪1007 天前
Redux和MobX在React Native状态管理中的优缺点对比
前端·javascript·react native·react.js·架构·前端框架
带娃的IT创业者7 天前
《AI大模型应知应会100篇》第68篇:移动应用中的大模型功能开发 —— 用 React Native 打造你的语音笔记摘要 App
人工智能·笔记·react native