17. Using Different Routes

17.1. Routing

In this chapter we will add routing so we can navigate to a specific FAQ item. First we will install react-router:

$ yarn add react-router-dom

Next we will define the routes we want to use. We will use the BrowserRouter to define our routes. We will have a view at the root and a view at /faq/1 where ‘1’ is the index of the FAQ item. Our new App.js will look like this:

 1import React, { Component } from "react";
 2import { Provider } from "react-redux";
 3import { createStore, applyMiddleware } from "redux";
 4import { BrowserRouter, Route } from "react-router-dom";
 5
 6import rootReducer from "./reducers";
 7import Faq from "./components/Faq";
 8import FaqItemView from "./components/FaqItemView";
 9import api from "./middleware/api";
10
11import "./App.css";
12
13const store = createStore(rootReducer, applyMiddleware(api));
14
15class App extends Component {
16  render() {
17    return (
18      <Provider store={store}>
19        <BrowserRouter>
20          <div>
21            <Route exact path="/" component={Faq} />
22            <Route path="/faq/:index" component={FaqItemView} />
23          </div>
24        </BrowserRouter>
25      </Provider>
26    );
27  }
28}
29
30export default App;

Differences

--- a/src/App.js
+++ b/src/App.js
@@ -1,9 +1,11 @@
import React, { Component } from "react";
import { Provider } from "react-redux";
import { createStore, applyMiddleware } from "redux";
+import { BrowserRouter, Route } from "react-router-dom";

import rootReducer from "./reducers";
import Faq from "./components/Faq";
+import FaqItemView from "./components/FaqItemView";
import api from "./middleware/api";

import "./App.css";
@@ -14,7 +16,12 @@ class App extends Component {
  render() {
    return (
      <Provider store={store}>
-        <Faq />
+        <BrowserRouter>
+          <div>
+            <Route exact path="/" component={Faq} />
+            <Route path="/faq/:index" component={FaqItemView} />
+          </div>
+        </BrowserRouter>
      </Provider>
    );
  }

17.2. Writing The View

Now we will create the FaqItemView component at components/FaqItemView.js. This will render the full FAQ item. The code will look something like this:

 1import React, { Component } from "react";
 2import PropTypes from "prop-types";
 3import { connect } from "react-redux";
 4
 5import { getFaqItems } from "../actions";
 6
 7class FaqItemView extends Component {
 8  static propTypes = {
 9    faqItem: PropTypes.shape({
10      question: PropTypes.string,
11      answer: PropTypes.string
12    }).isRequired
13  };
14
15  componentDidMount() {
16    this.props.getFaqItems();
17  }
18
19  render() {
20    return (
21      <div>
22        <h2 className="question">{this.props.faqItem.question}</h2>
23        <p>{this.props.faqItem.answer}</p>
24      </div>
25    );
26  }
27}
28
29export default connect(
30  (state, props) => {
31    // Todo
32  },
33  { getFaqItems }
34)(FaqItemView);

17.3. Exercise

React Router add a property called match to all nested components. This property contains all the information about the matched route including the parameters so props.match.params.index contains the index of the faq item. Complete the connect call to return the correct data:

Solution

29export default connect(
30  (state, props) => {
31    const index = parseInt(props.match.params.index, 10);
32    return {
33      faqItem: index < state.faq.length ? state.faq[index] : {}
34    };
35  },
36  { getFaqItems }
37)(FaqItemView);

To test your view navigate to http://localhost:3000/faq/0