javascript - Router 6 - 从父组件调用子组件函数

标签 javascript reactjs react-router react-router-dom

App.js

const router = createBrowserRouter([
  {
    path: '/',
    element: <MainHeader />, 
    children:[
      { index: true, element: <Home />, loader :loaderHome }, 
    ]
  }
])

const App = () => { 
  return <RouterProvider router={router} />; 
}

export default App;

MainHeader.js

import { Outlet, NavLink, useLocation } from 'react-router-dom';

const MainHeader = (props) => { 
  const testRef = useRef();
  const location = useLocation();
  return (
    <>
      <header className={styles['main-header']}>
        <NavLink to={location.pathname==='/' ? testRef.current.testHandler : '/event'}>
          Home3
        </NavLink>
        <Login />
      </header>
      <Outlet innerRef={testRef} />
    </>
  );
}

export default MainHeader;

Home.js

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

const Home = React.forwardRef((props, ref) =>
  useImperativeHandle(ref, () => {
    return {
      testHandler: testHandler
    }
  })

  // I had to useCallback to prevent this function from reloading when the useEffect loads
  const testHandler=async(e)=>{
    console.log('enter test handler')
  }

  return (
    ............
  );
})

export default Home;

我想要的 - 在 MainHeader.js 中,点击 NavLink 时,如果路线是 '/' 则调用函数 testHandlerHome.js(子级)中定义,否则转到路由 '/event'

我尝试使用 forwardRef 与函数组件一样执行此操作,这是我迄今为止所做的,但它不起作用。我尝试将 MainHeader.js 中的 Outlet 组件中的引用传递给 Home.js 来调用 testHandler 函数.

有什么想法吗?我必须修改 App.js 吗?还有其他方法可以从 MainHeader.js 调用 testHandler 函数吗?

这有效,感谢您的帮助:

App.js

const App=()=>{ 
  const mainHeaderToHomeRef=useRef();

  const router=createBrowserRouter([{
    path:'/',
    element: <MainHeader ref={mainHeaderToHomeRef} />, // wraps around all the child routes below
    children:[
      {index:true, element:<Home ref={mainHeaderToHomeRef} />, loader:loaderHome }, // index route ./
    ]
  }])

  return <RouterProvider router={router} />; 
}

export default App;

MainHeader.js

import React from 'react';
import { Outlet, NavLink, useLocation } from 'react-router-dom';

const MainHeader=React.forwardRef((props, ref)=>{ 
    const location = useLocation();

    const homeHandleClick=(e)=>{
        if(location.pathname==='/' && ref.current){
            e.preventDefault() // stop the link from navigating
            ref.current.homeHandler() // call func in Home.js
        }
    }

    return(
        <>
        <header className={styles['main-header']}>
            <h1>Rotten Tomatoes</h1>
            <NavLink to='/' onClick={homeHandleClick}>Home3</NavLink>
            <Login/>
        </header>
        {/* Outlet is the place where the child routes should be rendered to, i.e. all the 
        children components in App.js */}
        <Outlet/>
        </>
    );
})

export default MainHeader;

Home.js

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

const Home = React.forwardRef((props, ref) =>

  useImperativeHandle(ref, () => {
    return{homeHandler:homeHandler}
  })
  
  // I had to useCallback to prevent this function from reloading when the useEffect loads
  const homeHandler=useCallback(async(e)=>{
        console.log('home handler entered')
    },[]);

  return (
    ............
  );
})

export default Home;

最佳答案

看起来您使用 React.forwardRef() 将引用从父 MainHeader 组件传递到子 Home 组件是正确的。但是,您当前的实现存在一些问题。

首先,您尝试在 Home 中定义 testHandler 之前访问它。您应该在尝试通过 ref 传递 testHandler 之前定义它。此外,由于您通过 ref 传递 testHandler,因此您需要将其包装在 useCallback() 中,以确保在每个渲染上使用相同的函数实例。

其次,在 MainHeader 中,您尝试直接调用 testRef.current.testHandler,但在安装 Home 之前 testRef.current 将为 null。您需要添加一个检查以确保在尝试调用 testHandler 之前定义了 testRef.current。

import { useLocation } from 'react-router-dom';
import { useRef } from 'react';
import Login from './Login';

const MainHeader = (props, ref) => {
  const testRef = useRef();
  const location = useLocation();

  const handleClick = () => {
    if (testRef.current) {
      testRef.current.testHandler();
    }
  };

  return (
    <>
      <header className={styles['main-header']}>
        <NavLink to={location.pathname === '/' ? '#' : '/event'} onClick={handleClick}>
          Home3
        </NavLink>
        <Login />
      </header>
      <Outlet innerRef={testRef} />
    </>
  );
};

export default React.forwardRef(MainHeader);

Home.js:

import { forwardRef, useImperativeHandle, useCallback } from 'react';

const Home = forwardRef((props, ref) => {
  const testHandler = useCallback(() => {
    console.log('enter test handler');
  }, []);

  useImperativeHandle(ref, () => ({
    testHandler,
  }));

  return <div>Home Component</div>;
});

export default Home;

这里,MainHeader 接受一个 ref 参数并将其作为 innerRef 传递给 Outlet。在handleClick()中,我们在调用testHandler()之前检查testRef.current是否已定义。

在 Home 中,我们使用 useCallback() 定义 testHandler,并使用 useImperativeHandle() 将其传递给 ref。

我希望这对你有用。

关于javascript - Router 6 - 从父组件调用子组件函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/76081241/

相关文章:

javascript - 使用 <Route> 标签时内容消失

javascript - jQuery 1.3 - 设置属性值的问题

javascript - 比较2组对象的值

javascript - 如何将背景图像从本地文件夹添加到容器

node.js - ioHook on Electron 消耗太多 CPU。反正周围有吗?或者替代ioHook

javascript - 如何使用 react-router-dom 中的 Mocha 测试 `NavLink`

javascript - JavaScript 中的位移

javascript - 将透明度应用于悬停时的内联背景颜色

javascript - React-router 弄乱了请求 url

reactjs - 如何让reactjs/flux/react-router spa同构?