It would be useful to support functions as Children for the Nested Router.
I have a page that receives an id, I make an API request to get the info, and I need to use the same info for the nested routes. I currently can't, and I have to hit the API 3 times, since the parent also needs the data to render a title.
Example:
<Router>
<View.Site.Index path="/site/:id">
{site => [
<View.Site.Home path="/" site={site} />,
<View.Site.Config path="/config" site={site} />
]}
</View.Site.Index>
</Router>
Yeah we have the same requirement now. Would be nice to have a simple way to pass props from the parent Route to the nested children.
e.g.
const App = () => (
<Router>
<Checkout path="event/:eventid">
<Form path="/" />
<Success path="success" />
</Checkout>
</Router>
)
Checkout makes an API call to populate a header and some other stuff. Form and Success both need some of this response data, so would be nice to easily just pass those down as props rather than be forced to stick them in a global store.
@oliverjam Wouldn't it be possible to clone Checkout's children, like so? 馃
class Checkout extends React.Component {
render() {
return React.cloneElement(
children,
{ data: this.state.data }
)
}
}
@srph in this case you need to map it because is a list of children, like this:
{React.Children.map(children, child =>
React.cloneElement(child, { something: ... })
)}
But it doesn't work, it doesn't pass the props to the children
I ran into this today and found a workaround that works for me:
{React.cloneElement(this.props.children, {
children: React.Children.map(this.props.children.props.children, child => {
return React.cloneElement(child, { yourCustomProp: value })
}),
})}
It is very specific to Reach router and how it passes children
@josebalius yes, that solutions works, it would be nice to have it built-in the lib.
Thanks
I think this can be solved with just a nested Router.
The issue that I'm having right now is that the main route fetches data and the children depend on that data, when I go from one child route to another, the whole page refreshes and makes the main request again, e.g.
App.jsx
<Router>
<Site path="/site/:id/*" />
</Router>
Site.jsx
componentDidMount() {
// fetches the site
// componentDidMount gets called everytime I change the
// child route, e.g. from / to /config, from /config to /report, etc
}
...
const { loading, site } = this.state;
if (loading) return <div>Loading...</div>;
return <div>
<Link to="">
Home
</Link>
<Link to="config">
Configuration
</Link>
<Link to="report">
Report
</Link>
<Router>
<SiteHome path="/" />
<SiteConfig path="config" />
<SiteReport path="report" />
</Router>
</div>
Just trying to gain a bit of context here.
-app
--routes
----home (fetches data)
------form (receives data via props)
------message(receives data via props)
----about
In this scenario, passing props as usual would work. Though I feel as though I'm missing something 馃槄
Why is this still a problem, seems like it breaks normal patterns? Children as render prop and mapping children.
Maybe reach could provide a custom Children.map function?
One could always use a React Context (as an alternative to a global store or the ugly but working React.cloneElement solution). For example:
export const ParentContext = React.createContext(null);
In the parent component:
import { ParentContext } from "./context.js";
export const ParentComponent = ({ children, someProp, anotherProp }) => (
<>
<h1>Parent provides the context</h1>
<ParentContext.Provider value={{ someProp, anotherProp }}>
{children}
</ParentContext.Provider>
</>
);
In the child component:
import React, { useContext } from "react";
import { ParentContext } from "./context.js";
export const ChildComponent = ({ children, someProp }) => {
const { someProp } = useContext(ParentContext);
return (<h2>{someProp}</h2>);
}
Most helpful comment
I ran into this today and found a workaround that works for me:
It is very specific to Reach router and how it passes children