4

I set up an app with 3 pages, Home, Reptiles and Map.

My problem comes on the Reptiles and Map page. On the reptiles page, I display a list of species, each with a list of range countries and a link "See Map Here". When the user clicks on a country, I want the Map page to be shown with the selected country highlighted (I haven't implemented that yet, so, for now, I just want that country to be passed to the map page).

And when the user clicks on a "See Map Here" for a species, I want the Map page to be shown with all the range countries of that species to be highlighted. Right now I can pass in reptile and country props in the Route for react-router, but when I try to pass in the props in the link directly in the Reptlie.js file, I get the error Warning: Unknown prop reptile on tag.

Remove this prop from the element. Can someone help me figure out how to pass props to links directly in components? Also, how would you generate dynamic URLs? For example, map/species1 or map/country1?

I think my problem is in Reptiles.js. The version of react-router is 3.0.2

Below is my structure:

enter image description here

Below are some images: enter image description here enter image description here

Below is my code: router.js:

const routes = (
  <Router history={browserHistory}>
    <Route component={App}>
        <Route path="/" component={Home}/>
        <Route path="reptiles" name="reptiles" component={Reptiles}/>
        <Route path="map" name="map" component={Map} country="Taiwan" reptile="Beardy"/>
    </Route>
  </Router>
);

export default routes;

App.js:

class App extends Component {
  render() {
    return (
      <div className="container">
        <header>
          <span className="icn-logo"><i className="material-icons">code</i></span>
          <ul className="main-nav">
            <li><NavLink to="/">Home</NavLink></li>
            <li><NavLink to="/reptiles">Reptiles</NavLink></li>
            <li><NavLink to="/map">Map</NavLink></li>
          </ul>       
        </header>
        {this.props.children}

      </div>
    );
  }
}

export default App;

Reptiles.js:

const Reptiles = () => {
  let reptiles = ReptileList.map((reptile) => {
    return (
      <li className="reptile" key={reptile.id} >
        <img className="reptile-img" src={reptile.img_src} />
        <h3>{reptile.name}</h3>
        <h4> Range &nbsp; &nbsp; 
            <span className="seeMap">
                <NavLink to="map" reptile={reptile.id}>  
                See Map Here 
                </NavLink>
            </span>
        </h4> 
            {reptile.range.map(function(country,index) {
                // only add comma if it's not the last one
                return <span key={country}><NavLink to="map" country={country}> {(index < reptile.range.length-1)? country+',' : country} </NavLink></span> 
            })
            }

      </li>
    );
  }); 

  return (
    <div className="main-content">
      <h2>Reptiles</h2>
      <ul className="group">
        {reptiles}    
      </ul>
    </div>
  );
}

export default Reptiles;

Map.js

var Map = React.createClass({

  render: function() {


    return (
        <div>
            <h2>Country passed from props: {this.props.route.country} </h2>
            <h2>Reptile passed from props: {this.props.route.reptile} </h2>
        </div>
    )

    }

});



export default Map;
Saurabh
  • 2,655
  • 1
  • 20
  • 47
jhjanicki
  • 425
  • 1
  • 3
  • 11
  • I added all my code to this repo along with the goals of the map page to the readme: https://github.com/jhjanicki/react-reptile-app – jhjanicki Apr 05 '17 at 06:33

3 Answers3

7

In route.js, you can pass the parameter as follows:

<Route path="map/:countryName/:reptileId" component={Map} name="map" />

In Reptile.jsx,Pass the parameters selected like from props.country or from state wherever you have stored. Make sure to pass some default values in the link when not applicable. For example, for the country in the first link, I have passed all. You can pass according to your requirements. You can pass the parameters as:

<NavLink to={`map/${reptile.id}`}>      

<NavLink to={`map/${country}/${reptile.id`}>

and access these parameters through context in Map.jsx this.props.params.reptileId

More about parameters

Like in your case, the parameter reptile id is must in both the cases and country is needed only in the case where specific country is clicked. Hence you can make the parameter country optional and reptile id compulsory. You can follow this

<Route path="map/:reptileId(/:countryName)" component={Map} name="map" /> 

and then pass accordingly.

<NavLink to={`map/${reptile.id}`}>      

<NavLink to={`map/${reptile.id}/${country}`}> 
Community
  • 1
  • 1
Richa Garg
  • 1,888
  • 12
  • 23
  • I tested it and just to start off simple i only tried it for reptile. In router.js I changed route to: and in Reptiles.js I changed the NavLink to See Map Here but I'm getting this error: Warning: [react-router] Location "/map" did not match any routes. But I don't have a link to "map" anywhere. Any idea why? – jhjanicki Apr 05 '17 at 06:10
  • Does the reptile.id has any value? – Richa Garg Apr 05 '17 at 06:33
  • this is what I get in the url: http://localhost:8080/map/$%7Breptile.id%7D but the map page wouldn't open. just in case you need more details I created a repo github.com/jhjanicki/react-reptile-app – jhjanicki Apr 05 '17 at 06:35
  • Sure. Let me check! – Richa Garg Apr 05 '17 at 06:41
  • ES6 recommends usage of back ticks instead of quotes – Richa Garg Apr 05 '17 at 07:16
  • Access the params in url in Map.jsx through `this.props.params.reptileId` – Richa Garg Apr 05 '17 at 09:21
  • thank you for your help, I haven't been able to get it to work for some reason. I'm going to try to rewrite the code in ES5 to see if that makes a difference. – jhjanicki Apr 06 '17 at 06:01
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/140027/discussion-between-richa-garg-and-jhjanicki). – Richa Garg Apr 06 '17 at 06:05
1

You have three options:

  1. Put the parameters in the URL. This is by far the best default. e.g. you might have the url /map/beardy, or /map?name=beardy.
    You then access these in Map with props.params.whatever or parse props.location.search (e.g. using qs from npm).

  2. Use browserHistory.push's state argument which adds a hidden piece of data to the history frame. This preserves the ability to refresh the page, or go back and forward in history while preserving the data. The downside is that I can't send a link to someone else and have it load with the selection.

  3. Use redux or similar to store the data in memory. The data will be lost when the page refreshes. This is pretty bad.

Brigand
  • 84,529
  • 20
  • 165
  • 173
  • If i make changes to Reptiles.js: See Map Here and then what changes to router.js would I need to make? Currently that Map route is but when I only edit Reptiles.js it still doesn't work. How do I sync them? This is trying the 1st options, I still haven't attempted 2 and 3 – jhjanicki Apr 05 '17 at 04:50
  • @jhjanicki `path="map/:foo"` and then it'll be `props.params.foo` – Brigand Apr 05 '17 at 08:30
0

To your first question: "how to pass props to links directly in components?". You can't, you do have some workarounds like the ones mentioned in other answers like creating a url that has some data in it and then retrieve it from the url when you load the component. But you can't pass custom props through or .

However, you can pass custom props like you're doing in router.js, except that instead of

This is from your router.js

<Route path="reptiles" name="reptiles" component={Reptiles}/>

You could pass the props like this:

<Route path="/reptiles" render={() => <Reptiles name="reptiles" />} />

To your second question: "how would you generate dynamic urls?"

Suppose you're rendering your component in like this:

class App extends Component {
    render() {
        return (
            <Reptile subtype="foobar" />
        )
    }
}

Then in Reptile.js you could create dynamic urls like this:

class Reptile extends Component {
    render() {
        return (
            <div>
                <NavLink to={`/reptile/${this.props.subtype}`} />
            </div>
        )
    }
}
jpg7
  • 21
  • 1
  • 6