简体   繁体   中英

React Router 4 Pass props to dynamic component

I have a list of doctors and I am trying to dynamically render a details page when selected. I see most people recommend to pass props through the Route component, something like this:

<Route path={`${match.url}/:name`}
  component={ (props) => <DoctorView doctor={this.props.doctors} {...props} />}
  />

Though I'm not clear on where I should be executing this. I tried it in DoctorList and DoctorItem but that didn't work. So I've set the Route in the App component, and I am able select a doctor, which then renders the DoctorView component and display the match.params prop just fine. But how do I get the selected doctor data to DoctorView? I'm probably making this harder than it should be. Here is my code:

App.jsx

const App = () => {
  return (
    <div>
      <NavigationBar />
      <FlashMessagesList />
      <Switch>
        <Route exact path="/" component={Greeting} />
        <Route path="/signup" component={SignupPage} />
        <Route path="/login" component={LoginPage} />
        <Route path="/content" component={requireAuth(ShareContentPage)} />
        <Route path="/doctors" component={requireAuth(Doctors)} />
        <Route path="/doctor/:name" component={requireAuth(DoctorView)} />
      </Switch>
    </div>
  );
}

DoctorList.jsx

class DoctorList extends React.Component {
  render() {
    const { doctors } = this.props;
    const linkList = doctors.map((doctor, index) => {
      return (
        <DoctorItem doctor={doctor} key={index} />
      );
    });

    return (
      <div>
        <h3>Doctor List</h3>
        <ul>{linkList}</ul>
      </div>
    );
  }
}

DoctorItem.jsx

const DoctorItem = ({ doctor, match }) => (
  <div>
    <Link
      to={{ pathname:`/doctor/${doctor.profile.first_name}-${doctor.profile.last_name}` }}>
      {doctor.profile.first_name} {doctor.profile.last_name}
    </Link>
  </div>
);

DoctorView.jsx

const DoctorItem = ({ doctor, match }) => (
  <div>
    <Link
      to={{ pathname:`/doctor/${doctor.profile.first_name}-${doctor.profile.last_name}` }}>
      {doctor.profile.first_name} {doctor.profile.last_name}
    </Link>
  </div>
);

I have access to the list of doctors via Redux, I could connect the component, bring in the list and compare id's but that feels like a lot of unnecessary steps.

But how do I get the selected doctor data to DoctorView?

Keep in mind that having paths like /items and /items/:id creates a scenario where you might be landing on the details page first.

Do you:

a) fetch all the items anyways because you might go back to the list page?

b) just fetch that the information for that one item?

Neither answer is "correct" but at the end of the day you have three possible pieces of information:

1) the item id

2) a single item

3) a list of items (which may or may not contain all of the information you need for the details page)

Wherever you want to display the full details of an item, it needs to have access to that item via props. Putting all of the item details in the url would be arduous, plus it would make it impossible to do situation A.

Since you're using redux, it makes perfect sense grab the details of the item from the identifier in the url

export default 
  connect((state, props) => ({
    doctor: state.doctorList.find(doctor => 
      doctor.id === props.match.params.id
    )
  }))(DoctorView)

Does ^ seems like too many extra steps?

While the answer above solves the issue perfectly, I just want to add that using an inline function with component is not advised by react-router

Instead of doing:

<Route path={`${match.url}/:name`}
  component={ (props) => <DoctorView doctor={this.props.doctors} {...props} />}
  />

You should instead use it like:

 <Route path={`${match.url}/:name`}
  render={ (props) => <DoctorView doctor={this.props.doctors} {...props} />}
  />

This will prevent the same component from being created on every mount and instead use the same component and update the state accordingly.

Hope this will help someone

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM