18. Using Different Routes

18.1. Routing

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

yarn add react-router-dom

Next we will define the routes we want to use. We will use 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 { Provider } from "react-redux";
 2import { createStore, applyMiddleware } from "redux";
 3import { BrowserRouter, Route } from "react-router-dom";
 4
 5import rootReducer from "./reducers";
 6import Faq from "./components/Faq";
 7import FaqItemView from "./components/FaqItemView";
 8import api from "./middleware/api";
 9
10import "./App.css";
11
12const store = createStore(rootReducer, applyMiddleware(api));
13
14const App = () => {
15  return (
16    <Provider store={store}>
17      <BrowserRouter>
18        <div>
19          <Route exact path="/" component={Faq} />
20          <Route path="/faq/:index" component={FaqItemView} />
21        </div>
22      </BrowserRouter>
23    </Provider>
24  );
25};
26
27export default App;

Differences

--- a/src/App.js
+++ b/src/App.js
@@ -1,8 +1,10 @@
 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";
@@ -12,7 +14,12 @@ const store = createStore(rootReducer, applyMiddleware(api));
 const App = () => {
   return (
     <Provider store={store}>
-      <Faq />
+      <BrowserRouter>
+        <div>
+          <Route exact path="/" component={Faq} />
+          <Route path="/faq/:index" component={FaqItemView} />
+        </div>
+      </BrowserRouter>
     </Provider>
   );
 };

18.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 { useEffect } from "react";
 2import { getFaqItems } from "../actions";
 3import { useSelector, useDispatch } from "react-redux";
 4import { useParams } from "react-router-dom";
 5
 6const FaqItemView = () => {
 7  const dispatch = useDispatch();
 8  const faqItem = "Todo";
 9
10  useEffect(() => {
11    dispatch(getFaqItems());
12  }, [dispatch]);
13
14  return (
15    <div>
16      <h2 className="question">{faqItem.question}</h2>
17      <p>{faqItem.answer}</p>
18    </div>
19  );
20};
21
22export default FaqItemView;

18.3. Exercise

React Router has a hook called useParams which returns an object of key/value pairs of URL parameters. The return object contains all the params of the match route, including our index params. Remove the Todo string, and write a function for the useSelector hook to fetch the correct data from the store.

Solution

 7  const { index } = useParams();
 8  const dispatch = useDispatch();
 9  const faqItem = useSelector((state) =>
10    state.faq.length ? state.faq[index] : {}
11  );

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