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 状态,否则可能会导致逻辑混乱。

相关推荐
jxm_csdn1 天前
Expo Go 本地命令行编译 apk(Ubutnu22.04)
react native
红尘散仙2 天前
一套 Rust 核心,跑通 Tauri + React Native
react native·react.js·rust
光影少年2 天前
react的 useState 原理、批量更新机制
前端·react.js·掘金·金石计划
诚实可靠王大锤3 天前
React Native 输入框与按钮焦点冲突解决方案(rn版本0.70.3)
前端·javascript·react native·react.js
sealaugh326 天前
react native(学习笔记第四课) 英语打卡微应用(3)-ocr的文字转化成语音文件(tts)
笔记·学习·react native
wordbaby7 天前
如何封装一个生产级的 React Native 分页列表 Hook
前端·react native·react.js
光影少年9 天前
react 单向数据流理解
前端·react.js·掘金·金石计划
沐言人生9 天前
ReactNative 源码分析5——ReactActivity之启动RN应用
android·react native
沐言人生10 天前
ReactNative 源码分析4——ReactActivity之加载JSBundle
android·react native
沐言人生11 天前
ReactNative 源码分析3——ReactActivity之初始化RN应用
android·react native