react-router icon indicating copy to clipboard operation
react-router copied to clipboard

[Bug]: Context prop in Outlet is not working with `index` routes.

Open umarjavedse opened this issue 3 years ago • 9 comments

What version of React Router are you using?

6.1.1

Steps to Reproduce

Setup project using below nested routes.

useRoutes([
    {
        path: '/',
        element: <Layout />,
        children: [
            {
                path: 'user',
                children: [
                    { index: true, element: <User /> },
                    { path: 'add', element: <AddUser /> },
                ],
            },
        ],
    },
])

and then use <Outlet context={data} /> in <Layout/>

Expected Behavior

Fetch data using useOutletContext hook.

Actual Behavior

Getting undefined with useOutletContext hook.

umarjavedse avatar Dec 16 '21 12:12 umarjavedse

When context pass to Outlet component, it only can be obtain in child route. In the code above, the User component is the grandchild component of Layout, so it could not obtain the context prop.

liuhanqu avatar Dec 17 '21 02:12 liuhanqu

@timdorr If Outlet component don't have context prop, we can use React.useContext(RouteContext).outlet directly and not wrap with OutletContext.Provider, so the descendant components can get the context prop. In now, only the child component can get the context prop.

liuhanqu avatar Dec 17 '21 02:12 liuhanqu

You should be using the new useOutletContext(), not trying to access the route context directly.

timdorr avatar Dec 17 '21 03:12 timdorr

@liuhanqu thanks for response, if all nested child can access context then this feature make more sense.

Yes @timdorr I'm using useOutletContext() to access context.

umarjavedse avatar Dec 17 '21 12:12 umarjavedse

I use react-router-dom v6.0.2 does it support useOutletContext()

TranLong183 avatar Mar 31 '22 02:03 TranLong183

No, that is new as of 6.1.0. Please upgrade to a newer version, as you'll also get some bug fixes included.

timdorr avatar Apr 01 '22 01:04 timdorr

Hi just to confirm, is it currently possible to access a parent's context from a grandchild route?

I mean this kind of situation:

<Routes>
  <Route path="/" element={<Outlet context={{ someKey: 1 }} />}>
    <Route path="child" element={<Outlet context={{ otherKey: 1 }} />}>
      <Route index element={<GrandChildPage />} />
    </Route>
  </Route>
</Routes>

then can we access the context containing someKey from GrandChildPage?

tmokmss avatar Aug 15 '22 15:08 tmokmss

@tmokmss I believe accessing the context from GrandChildPage is not working with Outlet in this package for now might be doable in future. To perform that you need to create custom Outlet using useOutlet hook with Context Provider.

umarjavedse avatar Aug 16 '22 10:08 umarjavedse

Hi @umarjavedse thanks. Yeah I actually tried similar code as above but it did not work. As a workaround I found a way like this (manually inheriting a parent's context in a child context):

<Routes>
  <Route path="/" element={<Outlet context={{ someKey: 1 }} />}>
    <Route path="child" element={<Outlet context={{ ...useOutletContext(), otherKey: 1 }} />}>
      <Route index element={<GrandChildPage />} />
    </Route>
  </Route>
</Routes>

tmokmss avatar Aug 17 '22 03:08 tmokmss

This issue has been automatically marked stale because we haven't received a response from the original author in a while 🙈. This automation helps keep the issue tracker clean from issues that are not actionable. Please reach out if you have more information for us or you think this issue shouldn't be closed! 🙂 If you don't do so within 7 days, this issue will be automatically closed.

github-actions[bot] avatar Apr 25 '23 01:04 github-actions[bot]

Going to close this out as "working as expected" after chatting with @ryanflorence and @jacob-ebey.

<Outlet context> is really just a way to pass "props" to the direct child element since you aren't in charge of rendering the element itself - #7495

const routes = [{
  path: '/parent',
  element: <Parent />,
  children: [{
    path: 'child',
    element: <Child />
  }],
}];

function Parent() {
  // Since you can't do <Child prop={{ some: "value }} /> here, you can instead do:
  return <Outlet context={{ some: "value" }} />
}

function Child() {
  // Instead of receiving a `prop`, you can get the parent value from context
  let obj = useOutletContext();
  // obj => { some: "value" }
}

If you need to provide something for deeper access through multiple intermediate Routes - then that's what normal React.Context is for and there's no need to leverage an Outlet context abstraction.

brophdawg11 avatar May 24 '23 18:05 brophdawg11