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;
What I want – in MainHeader.js
, NavLink
when clicked, if the route is '/'
then call function testHandler
defined in Home.js
(child) otherwise go to route '/event'
.
I tried doing this using forwardRef
as with function components, this is what I have thus far but it isn’t working. I tried passing a ref in the Outlet
component in MainHeader.js
to Home.js
to call the testHandler
function.
Any ideas? Do I have to modify App.js
? Is there any other way to call the testHandler
function from MainHeader.js
?
2
Answers
It looks like you’re on the right track with using React.forwardRef() to pass a ref from the parent MainHeader component to the child Home component. However, there are a couple of issues with your current implementation.
Firstly, you’re trying to access testHandler before it’s defined in Home. You should define testHandler before you try to pass it through the ref. Additionally, since you’re passing testHandler through a ref, you’ll need to wrap it in useCallback() to ensure that the same function instance is used on every render.
Secondly, in MainHeader, you’re trying to call testRef.current.testHandler directly, but testRef.current will be null until Home has mounted. You’ll need to add a check to ensure that testRef.current is defined before trying to call testHandler.
Home.js:
Here, MainHeader takes a ref parameter and passes it to Outlet as innerRef. In handleClick(), we check if testRef.current is defined before calling testHandler() on it.
In Home, we define testHandler using useCallback(), and pass it through the ref using useImperativeHandle().
I hope this works for you.
It’s a huge React anti-pattern to call functions defined in other React components, typically indicative of a code smell.
Define
testHandler
higher in the ReactTree and pass down to the components where you are wanting to call it.Also,
testHandler
isn’t a validNavLink
to
prop value, so you will have problems trying to do what you are trying to do anyway. Add anonClick
handler to the"/event"
link that conditionally cancels the navigation action and callstestHandler
.Example:
App.jsx
MainHeader
Home