useEffect依赖项中的全局范围变量?
像‘window.location.pathname’这样的外部范围值不是有效的依赖项,因为改变它们不会重新渲染组件。 用例
假设我们必须在每个页面上执行一个操作,并且每当路由更改时我们都必须执行此操作。
由于我们必须在每个页面组件上执行操作,所以让我们将逻辑抽象为一个钩子。文件
index.js 文件包含具有两个页面的路由器配置 -> 主页和其他页面。
主页和其他页面仅呈现文本并调用公共 useLocation 挂钩。
在 useLocation 钩子中,我们将根据 window.location.pathname 执行一些操作,这是一个全局范围的变量。// FILENAME -> index.js import React from "react"; import { render } from "react-dom"; import { BrowserRouter as Router, Route, Link } from "react-router-dom"; import Other from "./components/Other"; import Home from "./components/Home"; // Basic Router to render Home Page and Other Page const BasicExample = () => (
); render(, document.getElementById("root"));// FILENAME -> useLocation.js // This is the hook that we will be running on each page import { useEffect } from "react"; const useLocation = (pathname) => { useEffect(() => { /* * If the pathname is same as current page path, perform some operation * For this example, the operation is to alert the user * only if pathname passed and window.location.pathname are equal */ if (pathname === window.location.pathname) { alert( `On Page -> , pathname -> ${pathname}, window.location.pathname -> ${window.location.pathname}` ); } }, [pathname, window.location.pathname]); }; export default useLocation;// Home Page import React from "react"; import useLocation from "../useLocation"; const Home = () => { useLocation("/"); return Home
; }; export default Home; // ---------------------------------------------------------------------- // Other Page import React from "react"; import useLocation from "../useLocation"; const Other = () => { useLocation("/other"); return Other
; }; export default Other;相互作用
在交互中,我们可以看到,一旦我们登陆主页,我们就会看到路径 -> "/" 的警告,然后导航到其他页面,我们会看到路径 -> "/other" 的警告。
一切似乎都很好,那么问题是什么? 问题
让我们修改代码以在效果运行完成后执行清理操作。
在修改后的代码中,我们会将警报作为清理操作的一部分。// FILENAME -> useLocation.js // This is the hook that we will be running on each page import { useEffect } from "react"; const useLocation = (pathname) => { useEffect(() => { /* * If the pathname is same as current page path, perform some operation * For this example, the operation is to alert the user * only if pathname passed and window.location.pathname are equal */ if (pathname === window.location.pathname) { // MODIFIED CODE HERE -> removed alert from this condition // doSomeOperation() } // MODIFIED CODE HERE -> CLEANUP OPERATION // Added the same alert here return () => { alert( `On Page -> , pathname -> ${pathname}, window.location.pathname -> ${window.location.pathname}` ); } }, [pathname, window.location.pathname]); }; export default useLocation;
现在让我们看看交互
当我们导航到其他页面时,主页效果已经完成运行并运行清理操作。
虽然我们希望路径和路径名相同,但在警报中我们有路径名 -> ‘/’ 和 window.location.pathname -> ‘/other’。
发生这种情况是因为 window.location.pathname 在清理操作开始时发生了变化。
当我们从其他页面导航回主页时,也会发生同样的事情。 解决方案
让我们修改代码以在依赖项中不使用 window.location.pathname ,而是使用钩子中定义的局部变量。// FILENAME -> useLocation.js // This is the hook that we will be running on each page import { useEffect } from "react"; const useLocation = (pathname) => { // MODIFIED CODE HERE -> Assigned path = window.location.pathname // Use this variable across the hook const path = window.location.pathname; useEffect(() => { /* * If the pathname is same as current page path, perform some operation * For this example, the operation is to alert the user * only if pathname passed and path are equal */ if (pathname === path) { // doSomeOperation() } return () => { alert( `On Page -> , pathname -> ${pathname}, window.location.pathname -> ${path}` // Use path instead of window.location.pathname ); } }, [pathname, path]); }; export default useLocation;
现在让我们看看交互
应用修复后,我们可以看到我们获得了正确且一致的值。
这是可行的,因为路径是每个hook实例的局部变量。 虽然它在初始化时被分配给 window.location.pathname,但只有在重新渲染时才会重新分配。
你遇到过这样的问题吗! 请在评论中让我知道!