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

相关推荐
前端拿破轮2 天前
ReactNative从入门到性能优化(一)
前端·react native·客户端
ideaout技术团队4 天前
android集成react native组件踩坑笔记(Activity局部展示RN的组件)
android·javascript·笔记·react native·react.js
洞窝技术5 天前
前端开发APP之跨平台开发(ReactNative0.74.5)
android·react native·ios
光影少年5 天前
React Native 第三章
javascript·react native·react.js
光影少年6 天前
React Navite 第二章
前端·react native·react.js·前端框架
月弦笙音7 天前
【React】19深度解析:掌握新一代React特性
javascript·react native·react.js
Amy_cx8 天前
搭建React Native开发环境
javascript·react native·react.js
_pengliang9 天前
React Native 使用 react-native-credentials-manager 接入谷歌登录教程
javascript·react native·react.js
诚实可靠王大锤11 天前
react-native实现多列表左右滑动+滚动TabBar悬停
javascript·react native·react.js·1024程序员节