Simple website tutorial – ReactJS + WordPress

Simple website tutorial – ReactJS + WordPress

I went trough lot of pain until I found a simple solution to build website on ReactJS. I have found multiple tutorials and used multiple resources to create simple way to do it.

Simple demo of what we will build in this tutorial (this demo is already styled) http://reactjs.netlime.eu/ What you will achieve in this tutorial is knowledge how to build clean ReactJS code that includes routing, page of article listing and article page. Back-end where data is stored is WordPress with WP REST API.

Technologies used in this ReactJS project

  1. WebStorm as IDE
  2. Windows 10 as operating system
  3. Installed NodeJS and NPM
  4. Installed node module “create-react-app” (npm install create-react-app)
  5. WordPress installed somewhere for example api.mydomain.com
  6. Installed WordPress plugin “WP REST API”

Setting up a ReactJS project

  1. Open WebStorm
  2. Create new project, project type “React App”
  3. In new project window you will need to set project location, node interpreter (it should be configured by default, if not search for node.exe in C:Program Filesnodejsnode.exe), and create-react-app package which is located at C:Program Filesnodejsnode_modulescreate-react-app
  4. Click create and wait until all required packages will be installed.

Setting up package.json file

I have mentioned that I had lot of pain to search for working solutions. This was because by default I had packages that were newer version than packages used in different tutorials and documentations.

Open package.json file and update dependencies section to be exactly like this:

"dependencies": {
  "react": "^15.4.2",
  "react-dom": "^15.4.2",
  "react-router": "3.0.0",
  "react-native-web": "0.0.80"
},

After that run “npm install” command again in project folder, this will update and reinstall dependencies

After it´s done, if you run command “npm start” after a while browser should open default ReactJS website which looks like this:

ReactJS Demo

Creating basic components for header, navigation and content

If you open App.js in src folder, you can see html:

<div className="App">
  <div className="App-header">
    <img src={logo} className="App-logo" alt="logo" />
    <h2>Welcome to React</h2>
  </div>
  <p className="App-intro">
    To get started, edit <code>src/App.js</code> and save to reload.
  </p>
</div>

This is the code which we will split up into components.

Header component

Create a file named Header.js in src with content

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
export default class Header extends Component {
    render() {
        return (<div className="App-header"><img src={logo} className="App-logo" alt="logo"/> <h2>Welcome to React</h2>
        </div> );
    }
}

As you can see, this Header.js component returns html for header, but with static fixed heading, let´s make it dynamic by adding constructor, where we will extract params passed to header and save it to component state and if param is not set then we will fall back to default “My website”. In render method we will set to display the heading. Code in Header.js should look like this:

import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
export default class Header extends Component {
    constructor(props) {
        super(props);
        this.state = {heading: this.props.heading ? this.props.heading : "My website"}
    }
    render() {
        return (<div className="App-header"><img src={logo} className="App-logo" alt="logo"/> <h2
            dangerouslySetInnerHTML={{__html: this.state.heading}}/></div> );
    }
}

Now we can finally replace html for header in App.js with header component. To do this we need to import our component by adding next line after import “./App.css”;

import Header from "./Header";

Now replace <div className=”App-header”>…..</div> with <Header heading=”Home page”/>  and now we can also remove “import logo from “./logo.svg” from App.js to avoid notices on compilation because its not used anymore. App.js file now should look like this:

import React, { Component } from 'react';
import './App.css';
import Header from "./Header";
class App extends Component {
  render() {
    return (
      <div className="App">
        <Header heading="Home Page"/>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    );
  }
}
export default App;


It´s time to test the changes, hit ctrl+c in terminal, type “y” now server should be stopped and ready to start up again by typing “npm start”, wait until it will start in browser and you should now see the same as before, but with title “Home page”. That means our Header component is working properly.

Creating Article listing component

For this we will need to create 2 files

  1. ArticleList.js
  2. ArticleListItem.js

Here I will place full code with comments for each line instead of adding pieces of code, this way its more readable.

// ArticleList.js
// Import required packages / components
import React from 'react';
import ArticleListItem from "./ArticleListItem";
// Define the component class
export default class ArticleList extends React.Component {
    // Create constructor
    constructor(props) {
        super(props);
        // Set default state
        // articles will be javascript array of objects
        // articleList will be array of ArticleListItem components
        this.state = {
            articles: "",
            articleList: "",
        };
    }
    // This function will make sure that our component will be
    // re-rendered after fetching for data
    async fetchData() {
        // Fetch for data, await fetch is native react alternative to $.get()
        // You can use my blogs api, it has allowed cross-origin
        const response = await fetch("https://www.netlime.eu/wp-json/wp/v2/posts");
        // Get convert json from request to array of objects
        const data = await response.json();
        // Update the component state with articles
        this.setState({articles: data});
        // Call create article list, that will create array of ArticleListItem components
        this.createArticleList();
    }
    // This function creates array of ArticleListItem components
    createArticleList() {
        // To prevent errors with empty variable, check if its not empty
        if (this.state.articles !== "") {
            // Create array of article list item components, by using map function on
            // articles that were fetched from server
            let articles = this.state.articles.map(function (article) {
                // Here we dynamically create ArticleListItem component.
                // Each component must have a key property that is unique identifier
                // of the component. Also we need to pass data to component which will be
                // displayed. 
                return (
                    <ArticleListItem
                        key={article.id}
                        id={article.id}
                        title={article.title.rendered}
                        desc={article.excerpt.rendered}
                    />
                );
            });
            // Now as we have generated array of ArticleListItems, update the sate with them
            this.setState({articleList: articles});
        } else {
            // Log message speaks for itself
            console.log("ArticleList.js: No articles to render or data is corrupted.");
            console.log(this.state.articles);
        }
    }
    // Start the fetching process here
    // Please see functions above to see the chain reaction it calls
    componentDidMount() {
        this.fetchData();
    }
    // Finally we can render our component
    render() {
        // Since we are doing async request for articles
        // the data is not available until request is not done.
        // In our case in this this case the articleList variable will be empty string.
        // So we will return html with loading data message to avoid errors, rendering empty
        // array of ArticleListItem.
        if (this.state.articleList === "") {
            return (
                <div className="articles container">
                    Loading data
                </div>
            );
        }
        // After fetching is done, the articleList will be not empty and 
        // render functions will be called again, so the previous Loading Data message
        // will be skipped and this code below will be executed and rendered.
        // This will render array of ArticleListItem components to the the browser
        return (
            <div className="articles container">
                <div>{this.state.articleList}</div>
            </div>
        );
    }
}


Now we just need to create ArticleListItem component, otherwise the web will not compile because of missing component. I will do the same thing, place full code here with comments.

// ArticleListItem.js
// Import required packages / components
import React from 'react';
import {Link} from 'react-router'
// Define the component class
export default class ArticleListItem extends React.Component {
    // Create constructor
    // Comment below is to disable notice about useless constructor
    // eslint-disable-next-line
    constructor(props) {
        super(props);
    }
    // Render our component
    render() {
        // Note that we will extract article id, title and description from properties that that we passed
        // in map function to this component in ArticleList.js
        // Dangerously set inner html is required to render elements like "-", "&",... or any html element.
        // As you may now for now, return in render function will render html and or components in return (...)
        // Quick note here for the <Link component, this will create a basic "<a href"
        // Quick note 2: Since we are using dangerouslySetInnerHTML, we will not adding code between tags, so 
        // <Link ...></Link> becomes <Link .../> (alias self closing tag) or <div ....></div> will be <div .../>
        return (
            <article>
                <div className="article">
                    <div className="image"></div>
                    <h1><Link to={"/articles/" + this.props.id} dangerouslySetInnerHTML={{__html: this.props.title}}/></h1>
                    <div dangerouslySetInnerHTML={{__html: this.props.desc}}></div>
                </div>
            </article>
        );
    }
}

Now we have both components required to render articles in App.js. In App.js change <p className=”App-intro”> into a <div className=”App-intro”> also don´t forget about closing tag </p> to </div>. Now replace content of this div with <ArticleList/> this will render our article list component, also we need to import our component by adding import ArticleList from “./ArticleList”;

App.js now should look like this:

import React, { Component } from 'react';
import './App.css';
import Header from "./Header";
import ArticleList from "./ArticleList";
class App extends Component {
  render() {
    return (
      <div className="App">
        <Header heading="Home Page"/>
        <div className="App-intro">
          <ArticleList/>
        </div>
      </div>
    );
  }
}
export default App;

Now if you re-run the server by ctrl+c and typing npm start  website should pop-up with list of articles like this:

simple reactjs website with article listing

You have probably noticed that titles is not clickable, and console is spammed by errors each time you click on title. This is because we still not have routing set up. Don´t worry about it, its our next step.

Setting up routing

Routing will work in way where when you access directly .com/articles/5 from  the browser then react router will render page of article with id 5 automatically (like if you visit any php website, its router will render corresponding page). Plus navigating on website will not reload the page.

This will require to edit index.js and creating Root.js

Modify index.js to look like this. Also read the comments in code

// index.js
// Import required packages / components
import React from 'react';
import ReactDOM from 'react-dom';
import Root from "./Root";
import App from './App';
import Article from "./Article";
import {Router, Route, IndexRoute, browserHistory} from 'react-router';
import './index.css';
ReactDOM.render(
    // <Router> components handles the routing
    // Using <Route> without path we define out wrapper for all routes
    // Our wrapper component will be called Root
    // We define it by adding parameter "component={Root}"
    // Then we define, that when we are on "/" path
    // It will be the IndexRoute and it will load our App component
    // We also want to have route for Article, so we define it by adding
    // <Route path="/articles/:articleId" component={Article}/>
    // This means if we type .com/articles/4  it will render component
    // Article with articleId of 4
    <Router history={browserHistory}>
        <Route component={Root}>
            <Route path="/">
                <IndexRoute component={App}/>
                <Route path="/articles/:articleId" component={Article}/>
            </Route>
        </Route>
    </Router>
    , document.getElementById('root'));

We are still not ready to rock and roll, because we still not have Root.js and Article.js, without them website will not work.

Create Root.js with content, read the code comments for explanation.

// Root.js
// Import required packages / components
import React from 'react'
// Define the component class
export default class Root extends React.Component {
    // Notice the render method will return a div with {this.props.children}
    // {this.props.children} is actually component defined in index.js in <Route component={FooBar} />
    // So if we are on IndexRoute it will render App.js, if we are on /article/XY it will render Article component
    render() {
        return (
            <div className="routerView">{this.props.children}</div>
        );
    }
}

Only last thing is required to make our application work without Menu in header is Article.js , read the code comments for explanation.

// Article.js
// Import required packages / components
import React from 'react';
import Header from "./Header";
// Define the component class
export default class Article extends React.Component {
    // Constructor to process input data from router
    // and to define defaults for component state
    constructor(props) {
        super(props);
        // Set the default state.
        // article_id will be of course article id, which we extract from properties of component.
        // The router components will pass "params" to component properties based on route definition.
        // We defined "/articles/:articleId" to our param with article will be articleId
        // state "article" defaults to empty string, it will be filled with data in fetchData function
        this.state = {
            article_id: this.props.params.articleId,
            article: ""
        };
    }
    // Fetch data from server asynchronously
    // For detailed descriptions what it does please see ArticleList.js
    // I don´t want to repeat myself
    async fetchData() {
        // Here is little difference, here we dynamically set article id in request to get single article
        const response = await fetch("https://www.netlime.eu/wp-json/wp/v2/posts/" + this.state.article_id);
        const data = await response.json();
        this.setState({article: data});
    }
    // For detailed descriptions what it does please see ArticleList.js
    // I don´t want to repeat myself
    componentDidMount() {
        this.fetchData();
    }
    render() {
        // For detailed descriptions what it does please see ArticleList.js
        // I don´t want to repeat myself
        // BUT! there is one more statement added "this.state.article === null"
        // This is because of fetchData fails, it will return null
        // I am not really fan of if(!this.state.article) sometimes it is required
        // to check for correct data type
        if (this.state.article === "" || this.state.article === null) {
            return (
                <div className="App">
                    <div className="container">
                        Loading data
                    </div>
                </div>
            );
        }
        // Since we have data from server, we can render the article
        // Here you can see that render has similar structure like in App.js
        // That means we have <div className="App"> we have our Header component where we pass the
        // article title. Then in container we put dangerously inner HTML. Why? See comment in Header component about it
        return (
            <div className="App">
                <Header heading={this.state.article.title.rendered}/>
                <div className="container">
                    <div className="content" dangerouslySetInnerHTML={{__html: this.state.article.content.rendered}}/>
                </div>
            </div>
        );
    }
}


Congratulations!

Now if you stop the server by ctrl+c (if its running) and start again by npm start  website will popup and you will have articles listed, with clickable title and when you click on title the article will be loaded, with article title in header and with article content in <div className=”content”…. />

Creating Navigation component

I am trolling. You now have all the knowledge to create navigation component. But I will write some guide to help a little.

First thing you need to do is to create file Navigation.js  and importing same things like in ArticleListItem.js and defining class with name Navigation. This class will only have 1 function and this function is the render() function. Inside render function will be just a return (…) and inside return (…) will be the html for your navigation. For example with structure div.navigation > ul > li > a

The <a href=”/”>Home Page</a> will be generated by the routing component like:

<Link to="/" activeClassName="active">Home Page</Link>

Currently you need just this one link in Menu, because if you go to article page, you can navigate back to Home Page where the article listing is by just clicking on “Home Page” in Menu, instead of using “back” button in browser.

When you have the Navigation component done. You will need to place it into Article.js and App.js below the <Header …/> or other pages in future.

Final words

I hope you understood basic principles how you can build website or webapplication just on react with routing (without page reload when navigating website) and without having to render anything using php or other programming language.

4 Comments

  • Bablofil

    Thanks, great article.

  • Gerhard M.

    Hi, thanks for the tutorial. It worked fine for me until it came to the end. Now I got last new js files.
    Than I got this Message:
    ‘Failed to compile
    ./src/index.js
    Module not found: Can’t resolve ‘react-router’ in ‘/usr/local/bin/archides/src’
    I already restarted the server, (from other help) deleted the packeage-lock.json file and reinstalled the system.
    But nothing worked.
    Any advice?
    Cheers

    • Erik Kubica

      Hi, it looks like you don´t have react router package installed, you need to install it by running “npm install” in project root directory that will install all missing packages that are specified in package.json, also check if your package.json is same as the one in article. Please note that version of react and react router my package.json is out of date and there were some changes how react router works. You can also check out code here https://github.com/erikkubica/reactjs-simple-blog-test which is the code for this page http://reactjs.netlime.eu/

  • Gerhard M.

    hi Erik,
    Thanks for your advice. After some struggles with dependencies it worked. Thanks for your help and this useful article. Cheers

Leave a Reply

Your email address will not be published. Required fields are marked *

*

*

*

Categories
You may also like
Search