React 自定义导航返回需双击问题排查与解决

react 自定义导航返回需双击问题排查与解决

正如摘要所述,本文将深入探讨 React 应用中自定义导航返回需双击的问题,并提供解决方案。

在 React 应用中实现自定义导航时,开发者可能会遇到需要点击两次返回按钮才能正确返回上一页面的问题。这通常与状态管理、URL 更新以及 window.history 的使用方式有关。下面我们将通过一个具体的例子来分析这个问题,并提供相应的解决方案。

问题分析

以下代码展示了一个使用 useEffect 钩子来管理状态、更新 URL 以及处理 popstate 事件的自定义 hook:

const useMyHook = (key) => {  const [st1, setSt1] = useState(null);  const [st2, setSt2] = useState(null);  const [initialLoad, setInitialLoad] = useState(true); // to find if it is loaded  useEffect(() => {    const storedFilters = JSON.parse(localStorage.getItem(key));    if (storedFilters && initialLoad) {      setSt1(storedFilters.st1);      setSt2(storedFilters.st2);    }    setInitialLoad(false); // once loaded set it to false  }, [initialLoad, key]);  useEffect(() => {    const updateQueryParams = () => {      const queryParams = new URLSearchParams();      if (st1) queryParams.set('state1', st1);      if (st2) queryParams.set('state2', st2);      const queryString = queryParams.toString();      const newUrl = `${window.location.pathname}?${queryString}`;      window.history.pushState({ path: newUrl }, '', newUrl);      localStorage.setItem(key, JSON.stringify({ st1, st2 }));    };    updateQueryParams();  }, [st1, st2, key]);  useEffect(() => {    const handlePopState = () => {      const queryParams = new URLSearchParams(window.location.search);      setApps(queryParams.get('state1') ? parseInt(queryParams.get('state1')) : null);      setLoc(queryParams.get('state2') ? parseInt(queryParams.get('state2')) : null);    };    window.addEventListener('popstate', handlePopState);    return () => {      window.removeEventListener('popstate', handlePopState);    }  }, []);  return { st1, setSt1, st2, setSt2 };};

问题在于,在开发环境下,React 的严格模式 (Strict Mode) 会导致组件被渲染两次。这意味着 useEffect 中的逻辑也会被执行两次。当用户点击返回按钮时,popstate 事件触发,handlePopState 函数被调用,状态被更新。但是,由于严格模式的影响,状态的更新可能并没有立即反映到 URL 上,导致第一次点击返回按钮时,URL 没有改变,第二次点击才能正确返回。

解决方案

解决此问题的一个方法是针对严格模式进行特殊处理,避免不必要的重复执行。更推荐的做法是,重新审视 useEffect 的依赖项和逻辑,确保它们只在必要的时候执行。

检查并优化 useEffect 的依赖项: 确保 useEffect 的依赖项列表只包含真正需要监听的变量。避免不必要的依赖项,可以减少 useEffect 的执行次数。避免在 useEffect 中执行副作用: 尽量将副作用操作移到 useEffect 之外,或者使用 useRef 来存储一些状态,避免在每次渲染时都执行副作用。考虑使用 useMemo 和 useCallback: 如果某些计算或函数是比较耗时的,可以使用 useMemo 和 useCallback 来缓存结果,避免重复计算。移除严格模式 (不推荐): 虽然可以移除严格模式来解决问题,但这会错过严格模式带来的潜在问题检测,因此不推荐。

示例代码优化

以下代码展示了一种可能的优化方案,通过检查 st1 和 st2 的变化,避免不必要的 URL 更新:

const useMyHook = (key) => {  const [st1, setSt1] = useState(null);  const [st2, setSt2] = useState(null);  const [initialLoad, setInitialLoad] = useState(true);  useEffect(() => {    const storedFilters = JSON.parse(localStorage.getItem(key));    if (storedFilters && initialLoad) {      setSt1(storedFilters.st1);      setSt2(storedFilters.st2);    }    setInitialLoad(false);  }, [initialLoad, key]);  const updateQueryParams = useCallback(() => {    const queryParams = new URLSearchParams();    if (st1) queryParams.set('state1', st1);    if (st2) queryParams.set('state2', st2);    const queryString = queryParams.toString();    const newUrl = `${window.location.pathname}?${queryString}`;    window.history.pushState({ path: newUrl }, '', newUrl);    localStorage.setItem(key, JSON.stringify({ st1, st2 }));  }, [st1, st2]);  useEffect(() => {    updateQueryParams();  }, [st1, st2, updateQueryParams]);  useEffect(() => {    const handlePopState = () => {      const queryParams = new URLSearchParams(window.location.search);      setSt1(queryParams.get('state1') ? parseInt(queryParams.get('state1')) : null);      setSt2(queryParams.get('state2') ? parseInt(queryParams.get('state2')) : null);    };    window.addEventListener('popstate', handlePopState);    return () => {      window.removeEventListener('popstate', handlePopState);    };  }, []);  return { st1, setSt1, st2, setSt2 };};

注意事项

在开发环境下,务必开启 React 的严格模式,以便及时发现潜在问题。仔细检查 useEffect 的依赖项,确保它们只包含真正需要监听的变量。避免在 useEffect 中执行不必要的副作用操作。合理使用 useMemo 和 useCallback 来优化性能。

总结

解决 React 自定义导航返回需双击的问题,需要深入理解 React 的生命周期和严格模式的特性。通过仔细分析代码,优化 useEffect 的使用方式,可以有效地避免此类问题。希望本文能帮助开发者更好地理解和解决 React 应用中的导航问题。

以上就是React 自定义导航返回需双击问题排查与解决的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1515819.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月20日 09:36:31
下一篇 2025年12月20日 09:36:46

相关推荐

  • JavaScript 的异步编程模型如何从回调地狱演进到 Async/Await?

    JavaScript异步编程从回调函数演进到async/await,解决了回调地狱问题。早期回调嵌套导致代码可读性差,Promise通过then/catch实现链式调用,改善了错误传播与任务组合,但仍不够直观。Generator尝试以yield实现同步风格写法,需额外执行器支持,未普及。async/…

    2025年12月20日
    000
  • JavaScript Node.js集群模式

    Node.js集群模式通过主进程创建多个worker进程共享端口,利用多核CPU提升并发处理能力。主进程管理worker生命周期,实现负载均衡与容错,适用于高并发Web服务,配合外部存储和PM2等工具可优化部署与稳定性。 在高并发场景下,Node.js 单进程的性能会受到 CPU 核心数的限制。虽然…

    2025年12月20日
    000
  • JavaScript中函数作为参数的执行机制解析

    javascript函数是第一类对象,可作为参数传递给其他函数。其执行方式取决于接收函数内部逻辑:有些函数仅将其作为数据处理(如`console.log`),而另一些则会调用它作为回调(如`array.prototype.sort()`)。理解这一机制对于编写高效的异步代码和高阶函数至关重要。 在J…

    2025年12月20日
    000
  • 使用 useParams 时 useEffect 意外执行的解决方法

    本文旨在解决在使用 React Router 的 `useParams` 钩子时,由于依赖项设置不当导致 `useEffect` 意外执行的问题。通过提取 `params` 对象中的特定属性作为依赖项,并添加必要的依赖项,可以避免不必要的副作用,提高组件的性能和可预测性。 在使用 React Rou…

    2025年12月20日
    000
  • JavaScript中函数作为参数的执行机制与回调函数详解

    本文深入探讨了javascript中函数作为一等公民的特性,以及它们如何作为参数被传递和执行。我们将详细解析当一个函数被作为参数传入另一个函数时,其行为如何由接收函数内部逻辑决定,并通过`console.log`和`array.prototype.sort`等具体示例,区分函数被视为数据值与被实际执…

    2025年12月20日
    000
  • Vue 3中Proxy对象的数据访问与组件通信实践

    本文旨在解决vue 3应用中通过异步请求获取数据并将其作为prop传递给子组件时,遇到的数据以`proxy(object)`形式显示且难以直接访问的问题。我们将深入探讨vue 3的响应式原理、异步数据处理的最佳实践,以及父子组件间数据传递的正确姿势,通过代码示例和详细解释,确保开发者能够顺畅地访问和…

    2025年12月20日
    000
  • 使用 useParams 时 useEffect 意外执行:依赖项问题及解决方案

    本文旨在解决在使用 React Router 的 `useParams` 钩子时,由于依赖项设置不当导致 `useEffect` 意外执行的问题。通过分析问题原因,并提供修改后的代码示例,帮助开发者避免此类错误,确保 `useEffect` 在预期的时间执行。 在使用 React Router 的 …

    2025年12月20日
    000
  • 安全地在客户端创建Stripe支付链接:可行性分析与替代方案

    本文探讨了在纯客户端环境下,不暴露Stripe密钥的前提下创建Stripe支付链接的可行性。由于Stripe API的安全机制,直接在客户端使用密钥存在安全风险。本文分析了该问题的本质,并提供了两种替代方案:预先生成固定支付链接或搭建后端服务动态生成。同时,建议根据具体业务场景考虑使用Checkou…

    2025年12月20日
    000
  • 基于多个数组数据计算结果排序的 React 教程

    本文档旨在解决在 React 应用中,如何根据两个独立数组中的数据计算结果对数据进行排序的问题。通过合并数据或使用映射对象,可以实现在排序时访问两个数组的信息,从而实现复杂的排序逻辑。本文将提供详细的代码示例和步骤,帮助开发者理解和应用这些方法。 在 React 应用中,经常会遇到需要根据多个数据源…

    2025年12月20日
    000
  • JavaScript中嵌套数组的过滤技巧:为何单层循环与内置方法足以胜任

    本文旨在阐明在JavaScript中过滤嵌套数组时,如何利用内置数组方法(如`indexOf`或`includes`)配合单层`for`循环高效地实现目标,而无需额外的嵌套循环或复杂的`if/else`结构。我们将深入探讨这些方法的工作原理,并通过代码示例展示其简洁性和实用性,帮助开发者更清晰地理解…

    2025年12月20日
    000
  • JavaScript嵌套数组过滤:理解单层循环与内置方法的效率之道

    在JavaScript中处理嵌套数组时,一个常见的疑问是:当需要根据子数组的内容进行过滤时,是否总是需要使用嵌套的`for`循环?对于许多初学者而言,直观的理解是,要访问嵌套数组中的每个元素,就必须使用两层循环。然而,在特定过滤场景下,JavaScript数组的内置方法能够极大地简化这一过程,使得一…

    2025年12月20日
    000
  • 如何在不暴露密钥的情况下在客户端创建Stripe支付链接

    本文旨在解决在纯静态网站环境下,如何在不暴露Stripe密钥的情况下,利用客户端代码创建Stripe支付链接的问题。由于Stripe API创建支付链接需要密钥,直接在客户端操作存在安全风险。本文将探讨不可行性,并提供预生成固定链接或使用后端服务的替代方案,以及推荐使用Checkout Sessio…

    2025年12月20日
    000
  • JavaScript嵌套数组过滤:揭秘单层循环与内置方法的效率之道

    本文深入探讨在javascript中过滤嵌套数组时,为何仅需一个`for`循环即可完成任务。通过解析`indexof()`和`includes()`等内置数组方法的内部工作机制,我们将理解它们如何独立处理子数组的遍历,从而避免了不必要的嵌套循环和`else`语句,简化代码并提高可读性。文章还将提供示…

    2025年12月20日
    000
  • 安全地在客户端创建Stripe支付链接:可行性分析与解决方案

    本文探讨了在完全静态的网站前端,不暴露Stripe密钥的情况下创建Stripe支付链接的可行性。分析了直接在客户端使用Stripe API的风险,并提出了两种替代方案:预先生成固定支付链接,或搭建后端服务动态生成支付链接。同时,建议对于高度个性化的购物车场景,直接使用Checkout Session…

    2025年12月20日
    000
  • JavaScript嵌套数组过滤:理解单循环与内置方法的强大

    在javascript中处理嵌套数组时,一个常见的需求是根据子数组的内容来过滤整个数组。例如,给定一个包含多个子数组的数组 `arr` 和一个目标元素 `elem`,我们可能需要返回一个新的数组,其中只包含那些不含有 `elem` 的子数组。初学者在面对这类问题时,常会疑惑是否需要使用双重 `for…

    2025年12月20日
    000
  • JavaScript条件返回优化:避免重复函数调用与提升代码简洁性

    本文探讨了在javascript中如何优雅地处理函数条件返回,避免因重复调用函数而导致的性能或逻辑问题。通过介绍在`if`语句中进行赋值以及利用逻辑或运算符`||`的短路特性,我们展示了两种简洁高效的实现方式,旨在提升代码的可读性和执行效率。 在日常的JavaScript开发中,我们经常会遇到这样一…

    2025年12月20日
    000
  • JavaScript 深拷贝的实现与应用:使用 structuredClone

    本文旨在提供一个可靠的 JavaScript 深拷贝实现方案,着重介绍 `structuredClone()` 方法,该方法能够完整复制包括嵌套属性和数组在内的对象。我们将详细讲解 `structuredClone()` 的使用方式,并通过示例代码展示其在深拷贝中的应用,确保原始对象与克隆对象之间的…

    2025年12月20日
    000
  • React Swiper 组件背景图片无法显示问题解决方案

    本文针对 React 项目中使用 Swiper 组件时,背景图片无法从本地目录加载显示的问题,提供了详细的解决方案。通过将图片资源放置于 `public` 目录下,并使用正确的相对路径或 `PUBLIC_URL` 环境变量,可以有效解决该问题,确保背景图片能够正确加载并显示在 Swiper 组件中。…

    2025年12月20日 好文分享
    000
  • 基于两个数组数据计算结果排序的 React 教程

    本文旨在解决 React 应用中,如何基于两个独立数组中的数据进行计算,并根据计算结果对数据进行排序的问题。通过将两个数据集根据唯一标识符进行合并,或在排序过程中引用映射对象,实现高效且灵活的排序功能。文章提供了详细的代码示例和步骤说明,帮助开发者理解和应用该技术。 在 React 开发中,经常会遇…

    2025年12月20日
    000
  • 如何将一组数值规范化到0-1范围:基于最大值的权重计算

    本教程详细介绍了如何将一组数值规范化到0-1的范围,其中最小值映射到0(或接近0),最大值映射到1。通过将每个数值除以集合中的最大值来实现,这在需要根据相对大小而非总和百分比来表示数据(如css透明度)时非常有用。 引言:理解数值规范化需求 在数据处理和前端开发中,我们经常需要将一组原始数值转换到一…

    2025年12月20日
    000

发表回复

登录后才能评论
关注微信