React中 useRef 和 useState 还能这样用?


大家好,我是 Range。今天给大家带来一篇团队金牌辅导老师 Uncle13 的原创文章。

useRefuseState 是 React 提供的两个钩子函数,用于处理组件状态和引用。虽然它们的主要目的不同,但可以在某些情况下结合使用,以管理复杂组件行为。

使用 useRef

  • 用于存储和访问 DOM 元素的引用。
  • 用于保存任何可变值,并在组件重新渲染时保持其稳定性。
  • 用于在多次渲染之间共享数据。

使用 useState

  • 用于在组件中维护状态。
  • 用于跟踪和更新数据。
  • 可以通过设置不同的初始状态来创建多个 useState 钩子。

以下是一些示例场景,说明何时以及如何使用 useRefuseState 来管理复杂组件行为:

  1. 操作 DOM 元素:如果你需要引用 DOM 元素并对其进行操作,可以使用 useRef 来保存对该元素的引用。例如,获取输入框的焦点、执行动画、测量元素的尺寸等。
import React, { useRef } from 'react';

function MyComponent({
  const inputRef = useRef(null);

  const focusInput = () => {
    inputRef.current.focus();
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={focusInput}>聚焦输入框</button>
    </div>

  );
}
  1. 保存之前的值:有时,你可能需要在组件重新渲染时保持某个值的稳定性。这可以通过 useRef 实现,因为 useRef 在多次渲染之间保持其引用不变。
import React, { useRef, useState } from 'react';

function MyComponent({
  const [count, setCount] = useState(0);
  const prevCountRef = useRef();

  useEffect(() => {
    prevCountRef.current = count; // 在每次重新渲染时更新 prevCountRef 的值
  });

  const increment = () => {
    setCount(prevCount => prevCount + 1);
  };

  return (
    <div>
      <p>上一次计数器值: {prevCountRef.current}</p>
      <p>当前计数器值: {count}</p>
      <button onClick={increment}>增加</button>
    </div>

  );
}
  1. 保存其他数据:如果你需要在组件重新渲染之间共享和访问数据,可以使用 useRef 来存储它。这些数据在重新渲染时不会触发组件重新计算。
import React, { useRef } from 'react';

function MyComponent({
  const dataRef = useRef({ name'John'age25 });

  const updateData = () => {
    dataRef.current.age += 1;
    console.log(dataRef.current);
  };

  return (
    <div>
      <p>Name: {dataRef.current.name}</p>
      <p>Age: {dataRef.current.age}</p>
      <button onClick={updateData}>增加年龄</button>
    </div>

  );
}

实际业务场景

有一个电商网站的商品详情页面,其中包含商品信息、评论列表和购买按钮。在这个场景下,我们希望能够追踪组件的渲染次数,同时又不引起额外的重新渲染。我们还希望能够管理多个状态值,以控制组件的不同方面。

解决方案

import React, { useRef, useState } from 'react';

function ProductDetail({
  const renderCount = useRef(0); // 使用 useRef 追踪渲染次数

  const [product, setProduct] = useState({
    name'iPhone 12',
    price999,
  });

  const [comments, setComments] = useState([
    { id1content'Great product!' },
    { id2content'Love it!' },
  ]);

  const handleAddComment = () => {
    const newComment = { id: comments.length + 1content'New comment' };
    setComments([...comments, newComment]);
  };

  renderCount.current += 1// 每次渲染递增渲染次数

  return (
    <div>
      <h1>商品名称: {product.name}</h1>
      <p>价格: ${product.price}</p>

      <h2>评论列表:</h2>
      <ul>
        {comments.map((comment) => (
          <li key={comment.id}>{comment.content}</li>
        ))}
      </ul>

      <button onClick={handleAddComment}>添加评论</button>

      <p>组件渲染次数: {renderCount.current}</p>
    </div>

  );
}

export default ProductDetail;

在上述示例中,我们创建了一个名为 ProductDetail 的函数组件。我们使用 useRef 钩子来追踪渲染次数,并将其存储在 renderCount 引用中。

同时,我们使用 useState 钩子来管理两个状态值:productcommentsproduct 状态保存了商品的名称和价格信息,而 comments 状态保存了评论列表。

当用户点击“添加评论”按钮时,我们通过 handleAddComment 函数向 comments 状态中添加一条新的评论。

最后,在组件的返回部分,我们将商品名称、价格、评论列表以及渲染次数展示在页面上。由于我们使用了 useRef 来追踪渲染次数,所以即使 comments 状态更新,也不会引发额外的重新渲染。

通过这个实际的业务场景的示例,我们可以看到如何使用 useRefuseState 结合来追踪组件的渲染次数,并且同时管理多个状态值,以控制组件的不同方面。

最后

也给我们的辅导服务打个广告,现在报名支持指定导师哦~