React中常用的hook函数(四)——useRef、useNavigate、useLocation和useSearchParams

一、useRef

1. 基础概念:

useRef 返回一个可变的 ref 对象,这个对象的 .current 属性可以用来存储一个值,该值在组件的生命周期内是持久化的,并且它不会导致组件重新渲染。

语法:
const myRef = useRef(initialValue);
  • initialValue:这是 useRef 的初始值,通常是 null 或者某个值。
  • myRef:这是返回的一个对象,具有 .current 属性,存储着你希望持久化的数据。

2. 用法 1:获取和操作 DOM 元素

比如,你可能需要在某个操作发生时聚焦一个输入框,或者读取一个 DOM 元素的尺寸信息等。

示例:访问 DOM 元素

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

const FocusInput = () => {
  const inputRef = useRef(null);

  useEffect(() => {
    // 组件加载完成后,自动聚焦到输入框
    inputRef.current.focus();
  }, []);

  return (
    <div>
      <input ref={inputRef} type="text" />
    </div>
  );
};

声明一个ref对象,通过input的ref属性将ref对象绑定,此时inputRef的current属性会指向该输入框的 DOM 元素

3. 用法 2:保持对数据的引用(不会触发重新渲染)

除了访问 DOM 元素,useRef 还可以用来存储其他可变的数据(例如计时器 ID、上一个值等),并且它不会引起组件重新渲染。

示例:持久化某个值

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

const TimerComponent = () => {
  const [seconds, setSeconds] = useState(0);
  const timerRef = useRef(null);

  useEffect(() => {
    timerRef.current = setInterval(() => {
      setSeconds(prev => prev + 1);
    }, 1000);

    // 清理计时器
    return () => clearInterval(timerRef.current);
  }, []);

  return (
    <div>
      <h1>{seconds} seconds</h1>
    </div>
  );
};
  • 在这个例子中,timerRef 用来存储计时器的 ID(一个可变的值)。即使 seconds 状态发生变化,timerRef 的值不会改变,它仅用来引用计时器。
  • useRef 允许我们避免因为 timerRef 的更新而导致不必要的组件重新渲染。

4. 用法 3:访问和持久化函数中的状态

有时你可能需要访问某个值的上一次状态。useRef 也能帮助我们存储一个值,在每次渲染时持久化下来,而不会因为它的改变导致重新渲染。

示例:记录上一个状态值

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

const PreviousState = () => {
  const [count, setCount] = useState(0);
  const prevCountRef = useRef();

  useEffect(() => {
    prevCountRef.current = count;
  }, [count]); // 每次 `count` 变化时,更新 `prevCountRef`

  return (
    <div>
      <h1>Current: {count}</h1>
      <h2>Previous: {prevCountRef.current}</h2>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
};
  • 在这个例子中,prevCountRef 用来存储 count 的上一个值。每次 count 更新时,prevCountRef.current 会持有之前的值。
  • 由于 useRef 的特性,prevCountRef 的改变不会导致组件重新渲染,所以它不会影响性能。

5. useRef 与 useState 的区别

  • useState:用于存储需要在 UI 上表现出来的状态。每当你调用 setState 更新状态时,React 会重新渲染组件。
  • useRef:用于存储不需要触发重新渲染的状态。它的值是持久化的,不会随着组件的重新渲染而改变。

总结

  • useRef 的 .current 属性在组件的整个生命周期内都保持不变。因此,您可以将它作为持久化存储来引用外部资源、DOM 元素或者数据,而不必担心它会导致组件重新渲染。
  • 如果你将 useRef 用作数据存储时,不要把它当作普通的 React 状态来使用。因为如果你直接改变 useRef 的值(例如 ref.current = newValue),这不会触发渲染更新,因此当你需要依赖于 UI 更新时,应该使用 useState 或者 useReducer

二、useNavigate

useNavigate 是 React Router v6 中的一个 Hook,用于在函数组件中进行编程式的导航。通过 useNavigate,你可以在没有用户直接点击链接的情况下进行路由跳转。它通常与事件处理函数或条件逻辑一起使用。

1. 基础概念:

useNavigate 返回一个函数,允许你在代码中进行路由跳转。该函数接受一个路径(可以是字符串)或一个包含导航选项的对象,并将页面重定向到相应的路由。

语法:
const navigate = useNavigate();

然后,你可以使用 navigate 来触发导航:

navigate('/new-path'); // 跳转到指定路径
navigate(-1); // 跳转到上一个历史记录(类似浏览器的返回按钮)
navigate('/new-path', { replace: true }); // 跳转,并替换当前的历史记录

2. 常见用法:

示例 1:基本导航

import React from 'react';
import { useNavigate } from 'react-router-dom';

const HomePage = () => {
  const navigate = useNavigate();

  const goToAbout = () => {
    navigate('/about'); // 编程式跳转到“/about”路径
  };

  return <button onClick={goToAbout}>Go to About</button>;
};

示例 2:带参数的导航

import React from 'react';
import { useNavigate } from 'react-router-dom';

const UserProfile = () => {
  const navigate = useNavigate();

  const goToProfile = (userId) => {
    navigate(`/profile/${userId}`); // 跳转到具体用户的个人页面
  };

  return <button onClick={() => goToProfile(123)}>Go to User 123's Profile</button>;
};

此例演示了如何将动态路径作为参数传递给 navigate,从而跳转到用户特定的页面。

3. 导航选项:

navigate 还可以接收一个对象作为第二个参数,允许你设置一些额外的导航选项,比如是否替换历史记录,或者传递状态数据。

示例 3:使用导航选项

import React from 'react';
import { useNavigate } from 'react-router-dom';

const LoginPage = () => {
  const navigate = useNavigate();

  const handleLogin = () => {
    // 登录成功后跳转到首页,并替换当前历史记录
    navigate('/', { replace: true });
  };

  return <button onClick={handleLogin}>Login</button>;
};
  • replace:如果设置为 true,则会替换当前历史记录,避免用户通过浏览器的“后退”按钮返回到此页面。
  • state:你还可以通过 state 传递一些状态数据,在导航后可以通过 location.state 访问这些数据。
navigate('/dashboard', { state: { from: 'login' } });

4. 后退和前进:

navigate 支持通过数字来实现类似浏览器历史记录的前进和后退操作。

示例 4:模拟浏览器的后退和前进

import React from 'react';
import { useNavigate } from 'react-router-dom';

const NavigationButtons = () => {
  const navigate = useNavigate();

  return (
    <div>
      <button onClick={() => navigate(-1)}>Back</button> {/* 后退 */}
      <button onClick={() => navigate(1)}>Forward</button> {/* 前进 */}
    </div>
  );
};
  • navigate(-1):后退一页,类似浏览器的“后退”按钮。
  • navigate(1):前进一页,类似浏览器的“前进”按钮。

5. 与其他 React Router 组件的结合使用:

useNavigate 可以与其他 React Router 组件(如 RouteLink 等)一起使用,来实现更复杂的导航逻辑。

示例 5:结合条件渲染导航

import React from 'react';
import { useNavigate } from 'react-router-dom';

const ProtectedPage = ({ isAuthenticated }) => {
  const navigate = useNavigate();

  if (!isAuthenticated) {
    // 如果没有认证,重定向到登录页面
    navigate('/login', { replace: true });
  }

  return <div>Protected Content</div>;
};

在这个例子中,如果用户未认证,将会在渲染时进行跳转。

6. useNavigate 与 useHistory 的区别

  • useHistory:在 React Router v5 中使用,提供一个历史记录对象,用来进行导航。
  • useNavigate:在 React Router v6 中替代了 useHistory,提供了更加简洁的 API(没有历史对象,直接返回一个 navigate 函数)。

7. 总结:

  • useNavigate 是 React Router v6 提供的用于编程式导航的 Hook,它简化了路由跳转的方式。
  • 使用 navigate 函数,你可以轻松地进行路径跳转、替换历史记录、或者实现类似浏览器“后退”与“前进”的功能。
  • useNavigate 提供了更多灵活的导航选项,可以使路由管理更加精细和高效。

三、useLocation

useLocation 是 React Router 提供的一个钩子(hook),用于访问当前的浏览器位置对象。这可以让你获取当前的 URL 路径、查询参数、哈希值等信息,从而在函数组件中实现基于路由的动态渲染。

主要特性:

  1. 返回位置对象: useLocation 返回一个位置对象 (location),包含以下几个主要属性:

    • pathname: 当前 URL 的路径部分(例如:/home)。
    • search: 查询字符串(例如:?id=123&name=abc)。
    • hash: 哈希值(例如:#section1)。
    • state: 传递的状态对象,通常用于在页面间传递一些非 URL 参数的数据。
  2. 用途:

    • 在 React 应用中动态地根据当前路径或查询参数更新 UI。
    • 实现路由相关的逻辑,比如基于 URL 路径变化显示不同的内容。
  3. 示例:

    import { useLocation } from 'react-router-dom';
    
    function MyComponent() {
      const location = useLocation();
    
      return (
        <div>
          <p>Current Path: {location.pathname}</p>
          <p>Query String: {location.search}</p>
          <p>Hash: {location.hash}</p>
        </div>
      );
    }
    
  4. 动态更新: useLocation 会随着浏览器的 URL 变化自动更新。如果你想监听路由变化,可以依赖 location 对象的变化来触发重新渲染。

  5. useHistory 比较:

    • useHistory 主要用于程序化导航,通过访问历史对象来控制跳转。
    • useLocation 关注的是获取当前的位置信息,通常用于展示和路由状态的读取。

使用场景:

  • 根据 URL 查询参数改变页面内容。
  • 在某些页面上根据路径进行特定的 UI 展示(例如,导航栏高亮显示)。
  • 处理哈希路由或者与后端交互时,根据不同路径做动态数据加载。

四、useSearchParams

useSearchParams 是 React Router v6 中提供的一个钩子(hook),用于读取和修改 URL 中的查询参数(即 ?key=value 的部分)。与传统的 window.location.search 不同,useSearchParams 提供了更方便的方式来处理查询字符串,同时支持 React Router 的状态管理和自动更新。 

主要特性:

1.返回值: useSearchParams 返回一个数组,包含两个元素:

  • searchParams: 这是一个 URLSearchParams 对象,允许你读取、修改查询参数。
  • setSearchParams: 这是一个函数,允许你更新查询参数并触发 URL 更新。

2.URLSearchParams 对象:

searchParams 是一个 URLSearchParams 实例,提供了多种方法来操作查询字符串

  • get(name): 获取某个查询参数的值(例如:searchParams.get('id'))。
  • getAll(name): 获取某个查询参数的所有值(对于重复参数,返回一个数组)。
  • set(name, value): 设置某个查询参数的值。
  • has(name): 检查查询参数是否存在。
  • delete(name): 删除某个查询参数。

3.示例代码:

import { useSearchParams } from 'react-router-dom';

function MyComponent() {
  // 获取当前的查询参数
  const [searchParams, setSearchParams] = useSearchParams();

  // 获取特定查询参数值
  const id = searchParams.get('id');
  const name = searchParams.get('name');

  // 修改查询参数
  const updateParams = () => {
    setSearchParams({ id: '456', name: 'John' });
  };

  return (
    <div>
      <p>Current ID: {id}</p>
      <p>Current Name: {name}</p>
      <button onClick={updateParams}>Update Params</button>
    </div>
  );
}

4.动态更新: useSearchParams 会随着查询参数的变化自动更新组件。如果查询参数发生变化,React 会重新渲染组件。你可以使用 searchParams 来读取当前查询字符串,使用 setSearchParams 来更新它。

5.更新查询参数: 当调用 setSearchParams 时,查询参数会被更新并触发页面的重新渲染。可以传递一个新的对象(例如 { id: '456', name: 'John' })来替换当前的查询参数,也可以传递一个函数来基于当前的查询参数进行更新。

setSearchParams(prev => {
  // 保留现有参数,修改某个字段
  prev.set('id', '456');
  return prev;
});

使用场景:

  • 控制分页和过滤器: 你可以利用查询参数(如 pagefilter)来控制内容的分页或筛选。
  • 分享链接: 在需要共享带有查询参数的链接时,useSearchParams 允许你动态地更改查询参数并更新 URL。
  • 维持 URL 状态: 在多个视图间保持查询参数一致,如在搜索功能中更新查询参数,以便用户刷新页面时仍然能看到相同的结果。
上一篇:探索 C++20:C++ 的新纪元


下一篇:go map