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 小时前
React Native DApp 开发全栈实战·从 0 到 1 系列(钱包全链路)
react native·web3
namehu17 小时前
🚀 2025 年最新教程:在 React Native 0.70+ 项目中接入 react-native-wechat-lib
react native·微信·taro
章丸丸3 天前
Tube - tRPC setup
react native·全栈
麦客奥德彪3 天前
React native 项目函数式编程的背后-另类的架构InversifyJS 依赖注入(DI)
react native·架构·客户端
冯志浩4 天前
React Native 中 useEffect 的使用
react native·掘金·金石计划
公众号_醉鱼Java4 天前
Elasticsearch 字段膨胀使用 Flattened类型
后端·掘金·金石计划
青红光硫化黑5 天前
React-native之组件
javascript·react native·react.js
冰冷的bin5 天前
【React Native】自定义跑马灯组件Marquee
react native
Bug改不动了5 天前
React Native 与 UniApp 对比
react native·react.js·uni-app