Im using React Router. In my state I have a number of TV shows identifiable by an ID. On the shows page I need to load the data for the specific show, matching the show ID to the end of the URL.
My state looks something like this but with more shows:
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 makes the :showID part of the URL available on the shows page . So I could pass my entire show state to the Show component and then find the correct show from the url. However I imagine this is inefficient?
I was wondering if I should look up the show via the ID in App.js and only pass the correct show to the Show component. Is this 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>
    )
  }
}
                As I see in your question, you are using Link to navigate. Considering you want to also send the data with the Link, you can pass an object to it instead of the string path as mentioned in the React-router docs, So you can pass the show information with the state object in TableRow component like
const {name, time, episodeId, img} = this.props;
<Link to={{pathname:showUrl, state: {show: {name, time, episodeId, img }}}}>{this.props.name}</Link>
Now you can retrieve this information in Show component as 
this.props.location.state && this.props.location.state.name
The other thing that you need to take care of is, that you need to pass the props to the render 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 work only if you navigate from within the App, but if you change the URL it won't work, if you want to make it more robust, you would need to pass the data to the show component and then optimise in the lifecycle 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 this is where libraries like redux and reselect are useful. with Redux your data shows will be in one common store and you can access it in any component and reselect gives you an option to create a selector that is memoized to get the appropriate show data from shows, so that the same calculation is not repeated again. Please explore about these and check if you find them a good fit for your project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With