React pass an object to the route - reactjs

I have this set up of my app in the ´app.js´ file I have my routers defined like this inside the render method
<HashRouter>
<StatusToast />
<Switch>
<Route
exact={true}
path="/"
render={props => (
<ImageScene{...props} title="Images & Information Search" />
)}
/>
<Route path="/case/:id/images" component={DetailsScene} />
</Switch>
</HashRouter>
from ImageScene on a table row click, I call a method like this:
this.props.history.push(/case/${id}/images)
this trigger a route and load DetailsScene where I can get the passed in id like this this.props.match.params.id all works without any problem so far.
My question is how can I pass a more than a string (the id) can I pass somehow the whole object to the route?
I have tried to do something like this for 2nd route instead of:
<Route path="/case/:id/images" component={DetailsScene} />
to set up on the ImageScene a method which can expose the selceted object, for now lets just do a simple one like:
export function getSelectedRow() {
return {
title: 'test'
}
}
and than set up the route like:
const object = getSelectedRow();
<Route path="/case/:id/images"
render={props => (<DetailsScene{...props} title={object.title} />
)}
/>
but I cannot make it work... any help would be graet, I'm totally new to react and the whole router.

you could add state to history.push (https://reacttraining.com/react-router/web/api/history) which is available for component being rendered (DetailsScene). Remember to wrap DetailsScene withRouter(...) to have history.location.state available in its props.

Related

React router does not render route when URL accessed directly

Consider this the main App component (imports left out for brevity):
const App = () => {
const [orderRoutes, setOrderRoutes] = useState([])
const updateOrderRoutes = (newRoute) => {
orderRoutes.push(newRoute)
setOrderRoutes(orderRoutes)
}
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
}
export default App
The challenge is that some of the routes are not known when rendering the initial App component. They will be known when an AJAX request in the <Header> component is responded to. The header will then update the new route to the orderRoutes state property, re-rendering the App component every time. The routes that are the result of the AJAX call (that is made in the <Header>) are then rendered to the <BrowserRouter> (in {renderedOrderRoutes}). In the <Header>, there is a <Link> for each route being rendered as a result of the same AJAX call, so that every menu entry (The <Link>s) will have a corresponding route.
This works fine, but when I access one of the URL's that this mechanism generates directly (e.g.: refresh the page), the <CatalogPage> component is not rendered.
So, for instance let's say that the AJAX call results in a bunch of routes and one of those is /t-shirts/tanktops. I will get a menu entry with a link to that path. When I click that menu entry the <CatalogPage> component is rendered. But when I access /t-shirts/tanktops directly, the <CatalogPage> component is not rendered.
How can I alter this code to make the URL's that are a result of the AJAX call directly accessible?
EDIT
OK, I 'solved' this (don't like it) by forcing the <App> component to re-render when one of the <Link>s was clicked by creating an unused piece of state on the App component called activeOrderRoute. I passed the setter down to the Header as a prop and connected it as a callback to the onClick handler for each Link that was created in response to the AJAX request. This essentially forces the App to re-render and render the routes, which solved my problems.
Still, that does not seem like the correct way to do it so any help would be appreciated.
React router does not directly have routing support for all URLs. It catches the default domain only the remaining routing is done on client side and requests are not served.
If your domain is www.mydomain.com, you can not access the URL www.mydomain.com/info directly in the react router.
Solutions:
You can use a hash router but that makes the URLs unfriendly for SEO
You can set up a catch-all routes and route it yourself
This link would help you with the same
https://ui.dev/react-router-cannot-get-url-refresh/
you need to modify your webpack.config.js and add the following lines.
module.exports = {
devServer: {
historyApiFallback: true,
},
...
Instead of trying to explicitly render a route for each asynchronously fetched route, leverage the power of react-router-dom and render a dynamic route path string that can handle any catalog page.
Instead of this:
const renderedOrderRoutes = orderRoutes.map(route => {
return (
<Route
path={`/${route.class}/${route.order}`}
exact
key={`/${route.class}/${route.order}`}
>
<CatalogPage />
</Route>
)
})
return (
<BrowserRouter>
<Header
updateOrderRoutes={updateOrderRoutes}
/>
<Route path="/" exact component={Home} />
<Route path="/aboutus" exact component={AboutUs} />
<Route path="/faq" exact component={Faq} />
<Route path="/register" exact component={Register} />
{renderedOrderRoutes}
<Footer />
</BrowserRouter>
)
Render a single dynamic route in your Router. Use a Switch so only a single route component is matched and rendered. Reorder the routes so the more specific paths can be matched before less specific paths. Now, when a URL has a path that is of the shape "/someClass/someOrder" it can be matched before you try matching any of the more general paths. You will see that the home path ("/") is matched last and the reordering allows us to remove the exact prop on all routes.
return (
<BrowserRouter>
<Header updateOrderRoutes={updateOrderRoutes} />
<Switch>
<Route
path="/:class/:order"
exact
component={CatalogPage}
/>
<Route path="/aboutus" component={AboutUs} />
<Route path="/faq" component={Faq} />
<Route path="/register" component={Register} />
<Route path="/" component={Home} />
</Switch>
<Footer />
</BrowserRouter>
)
You may need to adjust some logic in CatalogPage to handle possible undefined catalog data, whatever it is using from the route props/etc... to render catalog stuff.
In your Header component make the asynchronous call there to fetch the routes that can be navigated to so you can dynamically render render links to them (if that is even why you are passing the routes to Header).

How to pass data from functional component to class component in reactjs?

I want to pass data from my App.js file to a sub class component.I have tried with props,but its not workng at all
const org = 'Organization Dashboard'
const remotes = 'FromAdmin';
const DashboardContainer = ()=>(
<Sidebar org={org}>
<div className="App">
<Route path='/dashboard' component={Dashboard}/>
<Route path='/mytab' component={MyTab}/>
<Route path='/team' component={MyTeam}/>
<Route path='/settings' component={Settings}/>
<Route path='/logout' component={Logout}/>
<Route path='/team-settings/:param1' component={TeamSettings}/>
**<Route remotes='remotes' path='/user-settings/:param1' component={MyTab}/>**
</div>
</Sidebar>
)
I want to pass data in MyTab class component, when i use this.props in myTab , its showing undefined
Help will be appreciated
I assume you're trying to pass remotes='remotes' to MyTab. Components rendered by a Route are passed only the route props, but you can use an anonymous inner function to slip in extra props. Don't forget to pass on the route props if you need them!
<Route
path='/user-settings/:param1'
component={routeProps => <MyTab {...routeProps} remotes='remotes' />}
/>
You can override the component. By default, component accepts a class-based or function-based component. But you can override the component. Not only data you can pass functions as well. But you should not do this. Use redux to achieve this kind of thing. If it is static data then you can pass this way. But id it is dynamic data then use redux instead.
<Route
path = '/myTab'
component = {(props) => <MyTab {...props} data={data}/>}
/>

React Router don't pass value to match.props

So, I started learning React with Redux and react-router. Big mess for a .net
I want to use the match object to find the props in a given url, so I can do this:
function NumberHeader ({match}){
var number = match.props.nr;
..... Logic down here ...
}
I defined a route like this:
<Route path={`/number/:nr`} component={() => <NumberHeader match={this.props.match} />} />
The NumberHeader component is rendering at right url, but I can't get any props.
All this logic is happening not in the App root, it's happening in this rendered componen:
<Route path={routes.NUMERO} component={() => <DrawsPage />} />
What are the key factors that I need to folow, so this will work? I'm using the latest react-router v4. Thanks.
Pass the props from the component declaration:
component={props => <NumberHeader {...props} />}
Alternatively, just do
component={NumberHeader}

How to Pass Data Through My React-Router with ReactJS?

I have the following JSON object...
{ name: "Jessie" }
And I want to be able to pass it through my Router so that it can be displayed on my pages. For example, this is my root page...
StaticPage.jsx
export default class StaticPage extends React.Component {
render() {
return (
<div>
<Router history={hashHistory}>
<Route path='/' component={Search} />
<Route path='/favorites' component={Favorites} />
</Router>
</div>
);
}
}
So passing this data to Search, I would imagine might look something like this...
<Route path='/' component={Search} name = {this.props.name}/>
However, nothing gets rendered when I do that. I have researched this quite a bit and understand, from what I've read, that you cannot pass objects through the Router. It's very odd bc Router looks like a traditional React component but does not function as such. None of the explanations of a work around seem clear to me. Could anyone provide me with an example using this code? I am using react-router 3.0. There didn't seem to be any magical solution with 4.0 so I figured I'd ask before upgrading. Thanks!
It's because the component prop of <Route> only renders the component with route props, not your supplied props.
You can use the render or component prop on a <Route> in React Router v4 to pass a function which returns a <Search> element that explicitly passes the name:
<Route path="/" render={() => <Search name={this.props.name} />} />
Or with component:
<Route path="/" component={() => <Search name={this.props.name} />} />
But you should prefer render or else you'll have lots of remounting. If you still plan to use route props, you can also do:
render={routeProps => <Search name={this.props.name} {...routeProps} />}
A whole different approach, one more elegant in my opinion is to use route params and pass the name directly through the URL:
<Route path="/:name" component={Search} />
When you navigate to /Bob, you can access this.props.match.params.name which'll give you "Bob".
It is not a good practice to pass the object data via the routes directly. It is recommended to pass a param such as name or id in this way:
<Route path='/favorites/:name' component={Favorites} />
And retrieve it from your request in the destination.
This is a duplicate issue: Pass object through Link in react router

How to explicitly pass router params to React Component?

Does anyone have an idea how to pass the react-router params object explicitly to a component?
I want to make something like this, because unit testing would be easier if I could pass the ApiClient from outside:
function FooComponent() {
const apiClient = new ApiClient('http://foo.bar');
return (
<Bar apiClient={apiClient} param={?No idea how to pass the token param?} />
);
}
<Router history={history}>
<Route path="/test" component={Test} />
<IndexRoute component={TestIndex} />
<Route path="/validate/:token" component={FooComponent} />
</Router>
If your component is attached to the route ( i.e. set as the component prop of Route as in your provided code ), it receives a prop params from react-router where you can get the route and query parameters. In your case:
function FooComponent(props) {
const apiClient = new ApiClient('http://foo.bar');
return (
<Bar apiClient={apiClient} param={props.params} />
);
}
For official example, look at : https://github.com/ReactTraining/react-router/blob/master/examples/query-params/app.js
You can also consider something like this to pass down the router props and add some custom props to your component for example.
I don't know if it is documented somewhere in react-router documentation
<Route path="/campaign/overview" component={(routeProps) =>
<MyCoolComponent
myCustomApiKey="secret"
{...routeProps}
/>
}/>
You can now access this.props.params and this.props.myCustomApiKey in MyCoolComponent

Resources