Passing an object as prop in React-router Link - javascript

I'm getting the list of products in ProductList, in which, I need to pass the selected product object to Product.
Currently, I'm trying pass the id as a route param and get the product object again. But I want to send the entire product object from ProductList to Product.
My Route is
<Route path={joinPath(["/product", ":id?"])} component={Product} />
ProductList component Link
<Link to={"/product/" + this.props.product.Id} >{this.props.product.Name} </Link>
How to pass product object to Product as a prop?
the below one throws error in Typescript saying the following property does not exist on Link Type.
<Link to={"/product/" + this.props.product.Id} params={product}>{Name}</Link>
I tried the following questions, but none seems to have my issues.
Pass props in Link react-router
<--- this is similar to my issue, but answer doesn't work for react-router v4
react-router - pass props to handler component
React: passing in properties

The "to" property of Link can accept an object so you can pass your props like this :
<Link to={
{
pathname: "/product/" + this.props.product.Id,
myCustomProps: product
}
}>
{Name}
</Link>
Then you should be able to access them in this.props.location.myCustomProps

I would suggest using redux for retrieving the data. When you navigate to product route you can get the product details by dispatching some action.
componentDidMount() {
let productId = this.props.match.params.Id;
this.props.actions.getProduct(productId);
}
The product route should be connected with the the store.
Hope this helps.

You can try to do it through query params as in Pass object through Link in react router, which is quite ugly.
Also you can try to replace Link with some other element, e.g. button and in click listener do location change via browserHistory.push({ pathname:"/product/" + this.props.product.Id, state: this.props.product}) and and product as state property.

Related

this.props.match.params.id in React.js is undefined

I want to get the id from the URL therefore I can use this id to get and output the user info but I can't get id from URL. I've seen useParams() but I think it is not applicable with class component. May I know if there is an alternative solution for this?
async componentDidMount(){
const stud_id = this.props.match.params.id;
console.log(stud_id);
}
see error message from console here
The most common way of reading URL params in React is using React Router. In React Router, you get URL params with this.props.match.params like you are trying to, but you have to call your component inside a Route, like for example:
<Route
path="/:id"
component={YourComponent}
/>
instead of just
<YourComponent />
So that your component receives the match prop and can access this.props.match.params.id
If you're using
<Route path="/blah" component={()=><YourComponent someProp={someProp}>}/>
I mean, with arrow function as it child component, you have to pass the pros of the father (Route) to the child (YourComponent) like that:
<Route path="/blah" component={({match})=><YourComponent match={match} someProp={someProp}>}/>
Because you're creating a new "generation" so you have to pass the props by your self

react-router-dom <Link/> is clearing the {history,match,location} props when clicked in ssr application

I could not implement the Link component in server-side rendering.
<Link to={`/edit/${id}`}>
<h3>{description}</h3>
</Link>
In /edit page, I have this line of code to test the props that passed:
<h1>{props.match.params.id}</h1>
this throws an error because match prop is not passed.
If I used <a></a> instead of <Link/> wrapped /edit page with withRouter I get those props however this time I am disconnected from the store.
Since <Link/> navigates inside react-router looks like props that passed to components are cleared up when I click on <Link/>. I could not figure out how to solve the issue.
I added historyApiFallback:true to webpack.config devServer object but it did not solve the issue.
here is the repo
Your exact mistake is using href prop for the react-router Link component. you should use to, like below:
<Link to={`/edit/${id}`}>
<h3>{description}</h3>
</Link>
After fixing this issue, directly you will fall into another issue. you will get it inside EditExpensePage page:
const mapStateToProps = (state, props) => {
return {
expense: state.expenses.find(
expense => expense.id === props.match.params.id // here, you will get error the params of undefined
)
};
};
You will get params of undefined error because you wrap the withRouter by using react-redux connect, in fact, you should wrap react-redux connect by a withRouter:
export default withRouter(connect(mapStateToProps)(EditExpensePage));
After moving HOC wrapping the match key of props won't be undefined.

how to check if url param entered exist in location.pathname via React

Well, I try to understand legacy code with React routes onboard.
I have an url like
/home/reports/some_report_numbers
when user changes the ulr like that:
/home/reports/some_report_numb
I want to check if "some_report_numb" exists in props, in this.props.location.pathname. If exists - fine, go that way, otherwise go another way.
Maybe it is a wrong approach at all? Well, when the report is shown and user just deletes some letters in url I need to redirect to /home/ page. To do that I need somehow to check if that report with that numbers exists at all.
Maybe it could be done via
<Route name={SomeRouteName} path='reports/:reportId' component={HomePage} />
According to the documentation of react-router-dom
Link: https://reacttraining.com/react-router/web/example/url-params
match become an object that can be used in your component. Like explain in the documentation, you have access to match object with the following steps:
Route component as this.props.match
Route render as ({ match }) => ()
Route children as ({ match }) => ()
withRouter as this.props.match
matchPath as the return value
For example, if you have the following route:
<Route path="/reports/:reportId" component={HomePage} />
In your component, you can access to this with: this.props.match because it's an object and inside it, you will have what you want.
After that, you could check what params you have in your URL.
Now, if you want to redirect the user, you can use <Redirect to={'/your/path'} />

Passing optional parameter in react router

Say I have http://www.example.com/page/#/search routed like this:
<Router history={hashHistory}>
<Route path='/search/' component={SearchPage} />
</Router>
And when the user does a search on the page using the provided name and age search boxes (either can be left out, or both can be filled), I want it to redirect to:
http://www.example.com/page/#/search/?name=whatever%20name&age=15
Which will display the results for this particular search. This would also allow linking directly to search results.
Now inside my SearchPage component, how can I check if ?name= or ?age= or any other search parameters have been provided?
In your container say SearchPage you can access queryParams like this
this.props.location.query.yourKey.
As an example
class SearchPage extends React.Component{
componentWillMount(){
const {name, age} = this.props.location.query;
//here you can give default values if they are empty
//do whatever you want
}
}
There are two ways of achieving this either you can use params or query values.
By params:
In the route first define your optional parameters like this:
<Router history={hashHistory}>
<Route path='/search(/:name)(/:age)' component={SearchPage} />
</Router>
Include componentWillReceiveProps() method in your component it will get triggered whenever component receive any new props, like this:
componentWillReceiveProps(newProps){
console.log(newProps.params.name, newProps.params.age);
// here you can check the props value
}
In the component you can check the value by this.props.params.name or age.
By query parameter:
no change is required in the route, just pass the values in url and check like this:
this.props.location.name or age.
Read this article for about params and query values in react: https://www.themarketingtechnologist.co/react-router-an-introduction/
With the latest update "location.query" is not exposed, we have to use "location.search" to get the optional unnamed parameters. However, The named optional parameter still can be read through "props.match.params"
Route :
<Route path="/partner/list-space/step-1/:_id?" component={ListSpace}/>
Fetching the named optional parameter "id" in component or hooks
let id = props.match.params._id;
To fetch the unnamed optional parameter such as "space" from the url.
http://localhost:3000/partner/list-space/step-1/123?space=new&guests=4
We have to use "querystringify".
import qs from "querystringify";
const qsParams = qs.parse(props.location.search);
Results :
props.match.params._id => "123"
qsParams.space => new
qsParams.guests => 4

React Router Query Parameters

I have a React application which is using react-router v2.4. I have a route defined like so:
<Router history={this.props.history}>
<Route path="/:organisationId/objects"
component={ObjectsPage}
onEnter={(state) => {
this.props.dispatch(objectsFetch(
state.params.organisationId,
state.location.query
));
}}
/>
</Router>
Essentially, this route dispatches an action to fetch some objects from an API which are then rendered in a tabular format. I would like this table to be searchable, sortable and paginated and I think it would be appropriate to store the state of the table in the URL as query parameters so it can be refreshed and browser back/forward functionality isn't broken.
In order to update my table component I make a call to browserHistory with a URI similar to this (note the query parameters):
browserHistory.push('/0f08ac61-ddbd-4c73-a044-e71b8dd11edc/objects?page=2&search=query&sort=firstname|desc');
However, this doesn't trigger react-router into thinking the route has updated as the onEnter callback is never fired even though the browser history is updated with the new query string. I think I understand why this is happening; since the query string isn't part of the defined route I guess the package won't pick the change up.
Is there a way to use react-router with query parameters like this or will I have to make my filters part of the URI?
Need to use onChange in the route definition - onEnter is called the first time you hit a route and onChange is called when the route status changes:
<Route path="/:organisationId/patients"
component={PatientsPage}
onEnter={(state) => {
this.props.dispatch(patientsFetch(
state.params.organisationId,
state.location.query
));
}}
onChange={(state) => {
this.props.dispatch(patientsFetch(
state.params.organisationId,
state.location.query
));
}}
/>

Categories