通过分享链接访问组件时useLocation返回undefined的问题排查
我写了一个处理URL分享链接的组件,代码如下:
import { joinProject } from "@/service/project/ProjectService"; import { UserService } from "rd-component"; import React from "react"; import { useLocation, useNavigate } from "react-router-dom"; import queryString from 'query-string'; import { useSelector } from "react-redux"; import { AppState } from "@/redux/types/AppState"; const TeXShareRecieved: React.FC = () => { const navigate = useNavigate(); const location = useLocation(); const search = location.search; const params = queryString.parse(search); const pid = params.projectId!; const { joinResult } = useSelector((state: AppState) => state.proj); React.useEffect(() => { debugger if (!UserService.isLoggedIn()) { navigate("/user/login"); } handleJoin(); }, []); React.useEffect(() => { if (joinResult && Object.keys(joinResult).length > 0) { navigate("/editor?pid=" + pid) } }, [joinResult]); const handleJoin = () => { if (pid) { let joinReq = { project_id: pid as String }; joinProject(joinReq); } } return ( <div>Share</div> ); } export default TeXShareRecieved;
当用户打开分享链接(示例:http://dev-tex.example.top/proj/share?projectId=2f5c4956efcd45c0a7a385cac7ea0bc1)时会加载这个组件,我需要提取projectId参数并执行逻辑,但发现useLocation()返回undefined。想知道是不是遗漏了什么?是不是只有用navigate的时候才能访问参数?该怎么修复这个问题或者正确获取URL参数?
我的index.ts配置如下:
root.render( <React.StrictMode> <Provider store={store}> <RouterProvider router={routes} /> </Provider> </React.StrictMode> );
核心原因
useLocation返回undefined的根本原因是组件没有被包裹在React Router的路由上下文里。useLocation、useNavigate这类Router Hooks必须在RouterProvider提供的上下文范围内才能正常工作,如果TeXShareRecieved组件没有配置到routes路由表中,或者路由匹配规则错误,就会导致Hook无法获取到路由上下文。
具体修复步骤
检查并完善路由配置
确认你的routes对象里已经将/proj/share路径正确映射到TeXShareRecieved组件,示例配置如下:import { createBrowserRouter } from "react-router-dom"; import TeXShareRecieved from "./path/to/TeXShareRecieved"; const routes = createBrowserRouter([ { path: "/proj/share", element: <TeXShareRecieved />, }, // 其他路由配置... ]);只有组件通过
RouterProvider的路由表渲染时,才能正常获取路由上下文。安全获取URL参数
避免直接强制断言params.projectId!,增加空值判断防止报错:const pid = params.projectId as string | undefined; const handleJoin = () => { if (pid) { const joinReq = { project_id: pid }; joinProject(joinReq); } else { // 处理参数缺失情况,比如跳转到错误页 navigate("/error"); } }修复useEffect的依赖问题
第一个useEffect依赖数组为空,但内部用到了navigate和handleJoin,容易引发闭包问题,补全依赖并优化:const handleJoin = React.useCallback(() => { if (pid) { const joinReq = { project_id: pid }; joinProject(joinReq); } else { navigate("/error"); } }, [pid, navigate]); React.useEffect(() => { if (!UserService.isLoggedIn()) { navigate("/user/login"); return; // 未登录时终止后续逻辑 } handleJoin(); }, [navigate, handleJoin]);官方替代方案:使用useSearchParams
如果你用的是React Router v6+,可以直接用官方提供的useSearchParamsHook获取参数,无需额外依赖query-string库:import { useSearchParams } from "react-router-dom"; const TeXShareRecieved: React.FC = () => { const [searchParams] = useSearchParams(); const pid = searchParams.get("projectId"); // ...其他逻辑 }
内容的提问来源于stack exchange,提问作者Dolphin

