You will need to add react-router-dom
with npm
or yarn
. Once you add those, you will need to import some modules into your React app. You will need BrowserRouter
, Route
, NavLink
, & withRouter
.
BrowserRouter
is to be on the outmost parent Component that manages the history API. Ideally, you would just put your <App />
component inside it in your index.js
file, but I think it’s simpler to not include 3 separate files in my comment and just wrapped my <App />
response in it here instead.
Any component inside BrowserRouter
can use <Route />
and <NavLink />
. Route
will trigger based on the request URL and you change the request URL either by manually typing an address or using a <NavLink />
component. At the bottom of the Dropdown component you will see I export the component inside withRouter
. This adds useful information to the component’s props such as the current url slug.
Here is a simple example.
yarn add react-router-dom
// App.js
import React, {Component} from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import axios from 'axios';
import './App.scss';
import {wpAPI} from '../../data/api';
import FrontPage from '../../templates/FrontPage';
import Header from '../Header/Header';
import Post from '../Post/Post';
import Sidebar from '../Sidebar/Sidebar';
import Footer from '../Footer/Footer';
import Spinner from '../Spinner/Spinner';
// Create a React Component
class App extends Component {
state = {
pages: [],
posts: [],
postTypes: [],
acf: [],
events: [],
};
componentDidMount() {
var keys = Object.keys(this.state);
for ( var i = 0; i < keys.length; i++){
this.getPosts(keys[i]);
}
}
renderContent() {
if ( this.state.pages ) {
const {pages} = this.state;
return (
// Outermost element, contains single root child element.
<BrowserRouter>
<section id="app" className="animated fadeIn">
<Header />
<main>
// Path = Url after domain & protocal
// Use render prop to pass props to component, else use component prop ex. component={FrontPage}
<Route path="https://wordpress.stackexchange.com/" exact render={(props) => <FrontPage {...props} pages={ pages } /> } />
<Route path="/about" exact render={(props) => <Post {...props} post={ this.state.pages[3] } /> } />
</main>
<Sidebar />
<Footer />
</section>
</BrowserRouter>
)
}
return <Spinner message="loading..." />;
}
render() {
return this.renderContent();
}
/**
* Takes a post type, builds post type as array of post json in state
*
* @param {[string]} type [Post Type]
*/
getPosts = async (type) => {
const response = await axios.get(wpAPI[type]);
this.setState({[type]: response.data})
}
};
export default App;
.
// Menu.js
import React, {Component} from 'react';
import { library } from '@fortawesome/fontawesome-svg-core';
import { faChevronDown, faChevronUp } from "@fortawesome/free-solid-svg-icons";
import { NavLink, withRouter } from 'react-router-dom';
import './Dropdown.scss';
library.add(faChevronDown, faChevronUp);
class Dropdown extends Component {
constructor(props){
super(props)
const {title, list, to} = props;
this.state = {
listOpen: false,
title: title,
list: list,
to: to,
};
// console.log(this.state);
}
handleClickOutside(){
this.setState({
listOpen: false
})
}
toggleList(){
this.setState(prevState => ({
listOpen: !prevState.listOpen
}))
}
render() {
const {listOpen, title, list, to} = this.state;
if ( list ) {
return(
<div className="dropdown dropdown__wrapper">
<header className="dropdown__header" onClick={() => this.toggleList()}>
<div className="dropdown__title">{title}</div>
{listOpen
? <i className="fas fa-chevron-up"></i>
: <i className="fas fa-chevron-down"></i>
}
</header>
{listOpen && <ul className="dropdown__list">
{list.map((item) => (
<NavLink className="dropdown__item" key={item.id} to={item.to}>{item.title}</NavLink>
))}
</ul>}
</div>
);
}
return(
<div className="dropdown dropdown__wrapper">
<div className="dropdown__header" onClick={() => this.toggleList()}>
<NavLink className="dropdown__title" to={to}>{title}</NavLink>
</div>
</div>
);
}
}
export default withRouter(Dropdown);