Use url on component page to identify and pass data from parent using React Router?

Im using a React Router. In my condition, I have a number of television shows identified by ID. On the show page, I need to load data for a particular show by matching the show ID with the end of the URL.

My condition looks something like this, but with a lot of impressions:

shows: [ { id: 1318913 name: "Countdown" time: "14:10" }, { id: 1318914 name: "The News" time: "15:00" } ] 

In App.js:

 <BrowserRouter> <Switch> <Route exact path="/" render={() => { return <Table shows={this.state.shows} />; }} /> <Route path="/show/:showID" render={() => { return <Show />; }} /> <Route component={FourOhFour} /> </Switch> </BrowserRouter>; 

React Router does: showID the part of the URL available on the show page. That way, I could pass my show state to the Show component, and then find the correct show from the URL. However, I believe this is ineffective?

I was wondering if I would watch the show through ID in App.js and pass only the correct show to the Show component. Is this a better practice / more efficient?

Here is my table component:

 class Table extends Component { render(props) { return ( <table className="table table-striped table-bordered table-hover"> <tbody> { this.props.shows.map((item)=>{ return <TableRow name={item.name} time={item.time} key={item.eppisodeId} eppisodeId={item.eppisodeId} img={item.img} /> }) } </tbody> </table> ) } } 

Here is my TableRow component:

 class TableRow extends Component { render(props) { const image = this.props.img !== null ? <img src={this.props.img} alt={this.props.name} /> : null; const showUrl = '/show/' + this.props.eppisodeId; return ( <tr className="tableRow"> <td className="tableRow--imgTd">{image}</td> <td><Link to={showUrl}>{this.props.name}</Link></td> <td className="tableRow--timeTd">{this.props.time}</td> </tr> ) } } 
+5
source share
2 answers

As I see in your question, you are using Link for navigation. Given that you also want to send data using Link, you can pass an object to it instead of a string path , as specified in the React-router docs . Thus, you can pass the displayed information using the state object to TableRow , for example,

 const {name, time, episodeId, img} = this.props; <Link to={{pathname:showUrl, state: {show: {name, time, episodeId, img }}}}>{this.props.name}</Link> 

Now you can get this information in the Show component as

 this.props.location.state && this.props.location.state.name 

Another thing you need to take care of is that you need to pass the details into the rendering function

  <Switch> <Route exact path="/" render={(props) => { return <Table shows={this.state.shows} {...props}/>; }} /> <Route path="/show/:showID" render={(props) => { return <Show {...props}/>; }} /> <Route component={FourOhFour} /> </Switch> 

Now the above solution will only work if you are moving from the application, but if you change the URL, it will not work, if you want to make it more reliable, you will need to pass data to the show component and then optimize the life cycle functions

You would. do it like

 <Switch> <Route exact path="/" render={(props) => { return <Table shows={this.state.shows} {...props}/>; }} /> <Route path="/show/:showID" render={(props) => { return <Show shows={this.state.shows} {...props}/>; }} /> <Route component={FourOhFour} /> </Switch> 

And then in the Show component

 class Show extends React.Component { componentDidMount() { const {shows, match} = this.props; const {params} = match; // get the data from shows which matches params.id here using `find` or `filter` or whatever you feel appropriate } componentWillReceiveProps(nextProps) { const {match} = this.props; const {shows: nextShows, match: nextMatch} = nextProps; const {params} = match; const {params: nextParams} = nextMatch; if( nextParams.showId !== params.showId) { // get the data from nextProps.showId and nextShows here } } } 

However, libraries like redux and reselect . with Redux, your shows data will be in the same shared repository, and you can access it in any component, and reselect gives you the opportunity to create a selector that will be saved to get the corresponding Show data from shows , so the same calculation is not repeated again . Please study them and see if they are suitable for your project.

+2
source

A component parameter can take a function. If you pass the details, then using props.match.params.id you can find the identifier from the URL. Since we have a function, we can find the show from our state and pass it to the Show component.

 <BrowserRouter> <Switch> <Route exact path="/" render={() => { return <Table shows={this.state.shows} />; }} /> <Route path="/show/:id" component={(props)=>{ const foundShow = this.state.shows.find((show)=>{ const urlId = props.match.params.id; return show.eppisodeId === parseInt(urlId); }); // {...props} is optional, it will pass the other properties from React Router return <Show show={foundShow} {...props} /> }} /> <Route component={FourOhFour} /> </Switch> </BrowserRouter>; 

However, there is a strange behavior. If I console.log(this.props); in the Show component, then I see that it is displayed twice. The first time this.props.show empty, and the second time it has the data that I passed. This is a real pain, because I have to check for the presence of each variable before I draw it, which forces me to do what I have to do something wrong ...

UPDATE: the following solution to this problem, but I do not know if this is good practice:

 class Show extends Component { render(props) { if (this.props.foundShow) { const {name, network, time} = this.props.foundShow; return ( <div> <h2> {name} on {network} at {time} </h2> </div> ) } else { return ( <h2>Loading....</h2> ) } } } 
0
source

Source: https://habr.com/ru/post/1272528/


All Articles