在React中如何从其他组件调用被React Router渲染的Nav组件内的函数
解决方案
实现思路
使用React原生Context API,将Nav组件需要暴露的方法和关联状态提升到公共父组件App中托管,通过Context向所有后代组件注入方法,无需逐层传递props,任意层级的组件都可以直接消费Context调用目标方法,完全符合你要求的仅使用原生React、函数式组件的开发规则。
先修复原代码的几个已知问题
- App组件render方法没有返回JSX,也没有根元素包裹子组件
- Main.js重复导入PageOne,实际应该导入PageTwo
- PageOne.js中嵌套了BrowserRouter,全局仅需要在入口文件包裹一次BrowserRouter即可,重复嵌套会导致路由失效
- 原有类组件统一改为你要求的函数式组件
具体实现步骤
1. 新建全局上下文文件NavContext.js
import { createContext, useContext } from 'react'; // 创建Nav专属上下文 const NavContext = createContext(); // 封装自定义hook简化调用逻辑 export const useNav = () => useContext(NavContext); export default NavContext;
2. 修改App.js托管Nav的状态和方法
import React, { useState } from 'react'; import Nav from './Nav'; import Main from './Main'; import NavContext from './NavContext'; const App = () => { // 如果doSomethingToNav需要修改Nav外观,对应状态放在App层托管 const [navState, setNavState] = useState({}); const doSomethingToNav = () => { // 这里写你原有的Nav操作逻辑,比如修改样式、切换状态等 setNavState(prev => ({...prev, show: !prev.show})); }; return ( <NavContext.Provider value={{ doSomethingToNav, navState }}> <div className="app-wrapper"> <Nav /> <Main /> </div> </NavContext.Provider> ) } export default App;
3. 修改Nav.js消费上下文
import React from 'react'; import { NavLink } from 'react-router-dom'; import { useNav } from './NavContext'; const Nav = (props) => { // 拿到上下文里的状态和方法,Nav自身也可以正常调用 const { doSomethingToNav, navState } = useNav(); return( <nav style={navState}> <NavLink to="/pageone">Page One</NavLink> <NavLink to="/pagetwo">Page Two</NavLink> </nav> ) } export default Nav;
4. 修正Main.js导入错误
import React from 'react'; import { Route, Switch } from 'react-router-dom'; import PageOne from './PageOne'; import PageTwo from './PageTwo'; const Main = (props) => { return ( <main> <Switch> <Route exact path='/pageone'><PageOne /></Route> <Route exact path='/pagetwo'><PageTwo /></Route> </Switch> </main> ) } export default Main;
5. 修正PageOne.js移除嵌套路由
import React from 'react'; import { Switch, Route } from 'react-router-dom'; import SomeListOfItems from './SomeListOfItems'; import PageOneItem from './PageOneItem'; const PageOne = () => { return ( <Switch> <Route exact path='/pageone'> <SomeListOfItems /> </Route> <Route path="/pageone/:number/" component={PageOneItem} /> </Switch> ) } export default PageOne;
6. 修改PageOneItem.js实现两个场景的方法调用
import React, { useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useNav } from './NavContext'; const PageOneDetail = (props) => { const { doSomethingToNav } = useNav(); const navigate = useNavigate(); // 场景1:路由进入当前组件时调用方法 useEffect(() => { doSomethingToNav(); }, [doSomethingToNav]); // 场景2:点击关闭按钮时先调用方法再跳转 const handleClose = () => { doSomethingToNav(); navigate('/pageone'); }; return( <div> <button onClick={handleClose}>Close</button> <p>Some content...</p> </div> ) } export default PageOneDetail;
补充入口文件index.js配置
确保全局仅包裹一次BrowserRouter:
import React from 'react'; import ReactDOM from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <BrowserRouter> <App /> </BrowserRouter> );
内容的提问来源于stack exchange,提问作者mattinteractive
相关产品推荐
相关产品推荐

