Headless wp with react. How to handle routes?

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);