Simple User Authentication in React

Simple User Authentication in React

In this tutorial, you'll learn how to set up user authentication using React

In this tutorial, you'll learn how to set up user authentication using React

In 2019, it’s quite easy to find React components for pretty much everything. For example, if you want to add user authentication to your app, you can do so easily with Okta’s React component. Here I’ll walk you through creating a simple, fun React app that fetches random Chuck Norris jokes. I’ll then show you how you can add user authentication and customize your user experience, so the jokes will replace Chuck Norris’ name with their own.

Bootstrap Your React App

To get React up and running quickly without a lot of hassle, you can use React’s create-react-app script. React also prefers yarn if you have it installed. You can install those both with this command:

npm install --global [email protected] [email protected]


Once you have those installed, you can create a new app with the following:

create-react-app chuck-norris-jokes


The script will create a new directory with some starter files, install a slew of dependencies needed to get things up and running and initialize the project with git. You can now change into the directory and start the development server, which will open the app in your web browser. Your browser will automatically update whenever you change any source files.

cd chuck-norris-jokes
yarn start


Add Some Style to Your React App

First things first, you’ll need to change out the default logo. Since this will be showing Chuck Norris jokes, find your favorite image of Chuck Norris (or just use the one below).

Save the file to src/chuck-norris.png. Then open up src/App.js and change the line import logo from './logo.svg' to import logo from './chuck-norris.png'.

If you used the image above, the default dark background will make it hard to see. You also don’t really need his head to be spinning around, so open up src/App.css and make a few changes. You can get rid of the animation line (and you can get rid of the @keyframes block. You’ll also want to change the background-color to something like gray. You’ll want to add a button, but you can style it to look just like the Learn React link that’s already there. In the end, your CSS should look something like this (I also added a little padding to the header for small screens):

.App {
  text-align: center;
}

.App-logo {
  height: 40vmin;
  pointer-events: none;
}

.App-header {
  background-color: gray;
  padding: 10px;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

button.App-link {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  text-decoration: underline;
  cursor: pointer;
}


Use React Hooks to Fetch Some Jokes

With the release of React 16.8, you can now use hooks to make your code components a little simpler. It’s not totally necessary, but, why not? In your src/App.js, change the App component from a class to a function. The default looks something like this:

class App extends Component {
  render() {
    return (
      // ...
    );
  }
}


To make it a functional component, change it to look more like this:

const App = () => {
  return (
    // ...
  )
}


It’s not a huge difference, but it’ll allow us to add hooks in, which are a bit simpler than using the class lifecycle methods.

To add a piece of state with hooks, you’ll need to use the useState function exported from React. You’ll also be using useEffect later on, so you’ll need to make sure to import both of those. Change the line importing React to look like this:

Import React, { useState, useEffect } from 'react';


Then to use a piece of state, add the following to the top of your App function, before the return statement:

const [joke, setJoke] = useState('');


You now have a way to read a joke and change its value. By default, it will just be an empty string until you fetch it. Speaking of fetching, you can use The Internet Chuck Norris Database to fetch jokes. They come already encoded for HTML, but React expects strings to be decoded (e.g. " instead of "). You can install the he library to handle this for you, then import it using import { decode } from 'he'. Install it using:

yarn add [email protected]


Now you’ll need to write a function to fetch jokes. Since this will need to reference setJoke, it should be written inside the App component. The fetch API supports a signal that will allow you to cancel the call. This would be important to make sure calls come back in the right order. If you have two or three calls successively, you don’t really care about the first two, but instead, just want the final result.

const fetchJoke = async signal => {
  const url = new URL('https://api.icndb.com/jokes/random');
  const response = await fetch(url, { signal });
  const { value } = await response.json();

  setJoke(decode(value.joke));
};


You’ll also need an “effect” hook to fetch the joke whenever there isn’t one. The useEffect hook will run any time the component renders. However, you can add an array of values to watch, which will cause it to only run the effect when one of those values changes. In this case, you’ll only want to run the effect when the joke changes, or fetch one if there is no joke set yet. If the effect has a return value, it will be run when cleaning up the app, or before rendering again. Here is where you can provide a function that will cancel the fetch call.

useEffect(() => {
  if (!joke) {
    const controller = new AbortController();
    fetchJoke(controller.signal);

    return () => controller.abort();
  }
}, [joke]);


Now you just need to display the joke and add a button to fetch a new one. Clicking the button will set the joke back to an empty string, and the effect will take care of fetching a new joke. Replace the contents of the <p> tag with the joke (<p>{joke || '...'}</p>), and replace the <a> tag with a button:

<button className="App-link" onClick={() => setJoke('')}>
  Get a new joke
</button>


Your final code for App.js should look like this:

import React, { useState, useEffect } from 'react';
import { decode } from 'he';

import logo from './chuck-norris.png';
import './App.css';

const App = () => {
  const [joke, setJoke] = useState('');

  const fetchJoke = async signal => {
    const url = new URL('https://api.icndb.com/jokes/random');
    const response = await fetch(url, { signal });
    const { value } = await response.json();

    setJoke(decode(value.joke));
  };

  useEffect(() => {
    if (!joke) {
      const controller = new AbortController();
      fetchJoke(controller.signal);

      return () => controller.abort();
    }
  }, [joke]);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>{joke || '...'}</p>
        <button className="App-link" onClick={() => setJoke('')}>
          Get a new joke
        </button>
      </header>
    </div>
  );
}

export default App;


Add User Authentication to Your React App

Now that you have a functional web app, you can add some personalization by allowing users to sign in. One simple way to add authentication to your project is with Okta, which is what I’ll demonstrate. Our API enables you to:

If you don’t already have one, sign up for a forever-free developer account. Log in to your developer console, navigate to Applications, then click Add Application. Select Single-Page App, then click Next.

Since Create React App runs on port 3000 by default, you should add that as a Base URI and Login Redirect URI. Your settings should look like the following:

Click Done to save your app, then copy your Client ID and paste it as a variable into a file called .env.local in the root of your project. This will allow you to access the file in your code without needing to store credentials in source control. You’ll also need to add your organization URL (without the -admin suffix). Environment variables (other than NODE_ENV) need to start with REACT_APP_ in order for Create React App to read them, so the file should end up looking like this:

REACT_APP_OKTA_ORG_URL=https://{yourOktaDomain}
REACT_APP_OKTA_CLIENT_ID={yourClientId}


You may need to restart your server before it will recognize these changes. You can find the running instance and then hit ctrl-c to close it. Then run it again with yarn start.

The easiest way to add Authentication with Okta to a React app is to use Okta’s React SDK. You’ll also need to add routes, which can be done using React Router. Go ahead and add these dependencies:

yarn add @okta/[email protected] [email protected]


Now in order to use Okta in your React app, you’ll need to wrap the app in a provider. In your src/index.js, instead of rendering the <App /> component by itself, you’ll need to render a <Router> component. This uses React Router to control different URL paths in your app. Next, you’ll need to include the <Security> component as a child. This allows Okta to add an auth object to the context, which can be read from children in the React tree. Then you’ll need a couple Routes to let the router know what to display for each route. For the default route, you’ll display App, so everything should look the same as it did before. But you’ll also add an /implicit/callback route to let Okta handle the OAuth callback. Replace the call to ReactDOM.render with the following:

import { BrowserRouter as Router, Route } from 'react-router-dom';
import { Security, ImplicitCallback } from '@okta/okta-react';

ReactDOM.render(
  <Router>
    <Security
      issuer={`${process.env.REACT_APP_OKTA_ORG_URL}/oauth2/default`}
      client_id={process.env.REACT_APP_OKTA_CLIENT_ID}
      redirect_uri={`${window.location.origin}/implicit/callback`}
    >
      <Route path="/" exact component={App} />
      <Route path="/implicit/callback" component={ImplicitCallback} />
    </Security>
  </Router>,
  document.getElementById('root')
);


To tie Okta’s auth to a React component, you’ll need to wrap it in a withAuth, which adds an auth prop. Before you do that though, you can simplify things by again making use of hooks. Here I’ll have you create a custom hook that accepts the auth prop and returns the authenticated state as well as the current user. Create a new file src/auth.js that contains the following:

import { useState, useEffect } from 'react';

export const useAuth = auth => {
  const [authenticated, setAuthenticated] = useState(null);
  const [user, setUser] = useState(null);

  useEffect(() => {
    auth.isAuthenticated().then(isAuthenticated => {
      if (isAuthenticated !== authenticated) {
        setAuthenticated(isAuthenticated);
      }
    });
  });

  useEffect(() => {
    if (authenticated) {
      auth.getUser().then(setUser);
    } else {
      setUser(null);
    }
  }, [authenticated]);

  return [authenticated, user];
};


Here you’re using two pieces of state: authenticated and user, which both start out as null. Every time the component is rendered, the auth checks to see whether or not a user is authenticated. If authentication has changed, it updates the state. Initially, it will be null, but after the first time, it will always be either true or false. Whenever the authenticated state changes, that will trigger a call to get more information about the user. If the user isn’t authenticated, you can skip the check and simply set the user to null.

Back in src/App.js, you’ll need to import both the withAuth higher order component that Okta provides, and your new useAuth hook.

import { withAuth } from '@okta/okta-react';
import { useAuth } from './auth';


Wrap the App with withAuth and change the function to accept an auth param. Previously we had:

const App = () => {
  // ...
}


Now you should have:

const App = withAuth(({ auth }) => {
});


Add the new hook below the joke state:

const [authenticated, user] = useAuth(auth);


You can now add a new button after the “Get a new joke” button. When the authenticated variable is null, that means Okta hasn’t initialized yet so you’re not sure if the user is logged in or not. You could show some sort of loading indicator, or you could simply not render the button until you’re sure about the state of authentication:

{authenticated !== null && (
  <button
    onClick={() => authenticated ? auth.logout() : auth.login()}
    className="App-link"
  >
    Log {authenticated ? 'out' : 'in'}
  </button>
)}


Now the user can log in or out, but it doesn’t really do anything besides changing the button from “Log in” to “Log out”. The ICNDb API supports adding a first and last name to the URL, which replaces Chuck Norris with that name. Before the call to fetch, modify the url if there is a user:

if (user) {
  url.searchParams.set('firstName', user.given_name);
  url.searchParams.set('lastName', user.family_name);
}


Lastly, add a new effect to reset the joke whenever the user state changes. This will cause the app to fetch a new joke with the user’s name after they’ve logged in, or a default Chuck Norris joke when the user logs out.

useEffect(() => {
  setJoke('');
}, [user]);


Your final code should look like this:

import React, { useState, useEffect } from 'react';
import { decode } from 'he';
import { withAuth } from '@okta/okta-react';

import logo from './chuck-norris.png';
import './App.css';
import { useAuth } from './auth';

const App = withAuth(({ auth }) => {
  const [joke, setJoke] = useState('');
  const [authenticated, user] = useAuth(auth);

  const fetchJoke = async signal => {
    const url = new URL('https://api.icndb.com/jokes/random');
    if (user) {
      url.searchParams.set('firstName', user.given_name);
      url.searchParams.set('lastName', user.family_name);
    }
    const response = await fetch(url, { signal });
    const { value } = await response.json();

    setJoke(decode(value.joke));
  };

  useEffect(() => {
    if (!joke) {
      const controller = new AbortController();
      fetchJoke(controller.signal);

      return () => controller.abort();
    }
  }, [joke]);

  useEffect(() => {
    setJoke('');
  }, [user]);

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>{joke || '...'}</p>
        <button className="App-link" onClick={() => setJoke('')}>
          Get a new joke
        </button>
        {authenticated !== null && (
          <button
            onClick={() => authenticated ? auth.logout() : auth.login()}
            className="App-link"
          >
            Log {authenticated ? 'out' : 'in'}
          </button>
        )}
      </header>
    </div>
  );
});

export default App;


Learn More

Full Stack Developers: Everything You Need to Know

Learn React.js for Beginners

React Hooks Tutorial for Beginners: Getting Started With React Hooks

Learn React - React Crash Course 2019 - React Tutorial with Examples

Comparing the React and Vue Ecosystems with a Real-World SPA

React Router: Add the Power of Navigation

How to publish a React Native component to NPM

React - The Complete Guide (incl Hooks, React Router, Redux)

Modern React with Redux [2019 Update]

React Native - The Practical Guide

MERN Stack Front To Back: Full Stack React, Redux & Node.js

Full-Stack Web Apps with Meteor and React

React Hooks

Pagination in ReactJs

Pagination in ReactJs

There are a lot of resourceful materials online that give good insights into pagination in ReactJs, as well as NPM packages you can easily use

There are a lot of resourceful materials online that give good insights into pagination in ReactJs, as well as NPM packages you can easily use. As much as I appreciate those materials and love to use those packages, they mostly deal with loading the whole dataset on the page first then completely handle the pagination in the frontend. I am approaching this article with the concept of loading the exact data needed on the page, then manually loading other dataset based on the request when the user clicks the pagination number display. Below is the content structure to guide us through this article:

Table of Contents
  • Project Setup
  • HTML and CSS Styling
  • Pagination Data Format
  • Sample API request
  • Displaying the initial data
  • Showing Page Number and getting Other data
Project Setup

We are going to use create-react-app v0.1.0 which has the CSS Module configured already. Open your terminal and cd to the folder you want the project installed. Then run the below command:

npx create-react-app pagination  --use-npm

The above command will download the project into the folder calledpagination. You need to cd into the folder and run npm start. If everything goes well, you will have a page that looks like below:

HTML and CSS Styling

Open the project in your favorite code editor and locate the App.js file, We need to prepare our App.js to the look exactly like the way we want it by adding the HTML code and CSS style below:

Create a new file called App.module.css in the same directory where you have your App.js, then import it into your App.js using:

import styles from './App.module.css';

I want us to handle the display of the pagination number first, below is the style and HTML structure of what we are going to use.

  render() {
    

    return (
      <div className={styles.app}>
        
        <table className={styles.table}>
          <thead>
            <tr>
              <th>S/N</th>
              <th>First Name</th>
              <th>Last Name</th>
            </tr>
          </thead>
          <tbody>
              <tr>
                <td>1</td>
                <td>Abel</td>
                <td>Agoi</td>
              </tr>
              <tr>
                <td>2</td>
                <td>Muyiwa</td>
                <td>Aregbesola</td>
              </tr>
              <tr>
                <td>3</td>
                <td>Opeyemi</td>
                <td>Agoi</td>
              </tr>
              <tr>
                <td>4</td>
                <td>Ope</td>
                <td>Aina</td>
              </tr>
          </tbody>
        </table>


        <div className={styles.pagination}>
          <span>&laquo;</span>
          <span className={styles.active}>1</span>
          <span>2</span>
          <span>3</span>
          <span>4</span>
        </div>

      </div>
    );
  }

pagination_01.js

Add the content below into your App.module.css.

.app {
    width: 50%;
    margin: 0 auto;
}

table {
  border-collapse: collapse;
  border-spacing: 0; 
}


table {
  border-collapse: separate;
  border-spacing: 0;
  color: #4a4a4d;
  font: 14px/1.4 "Helvetica Neue", Helvetica, Arial, sans-serif;
  width: 100%;
}
tr {
  overflow-x: scroll;
}
th,
td {
  padding: 15px 15px;
  vertical-align: middle;
  /* text-align: left; */
}
thead {
  font-size: 14px;
  line-height: 24px;
  font-family: Lato;
  border: 1px solid transparent;

  max-width: 100%;
  font-weight: 900;
  line-height: 24px;
  mix-blend-mode: normal;

  color: rgba(51, 51, 51, .5);
  background: rgba(255, 255, 255, .9);
}
thead tr th {
  padding: 15px 15px;
  border: 1px solid transparent;


  text-align: left;
}
tbody {
  max-width: 100%;
}
tbody tr:nth-child(odd) {
  background: #f0f0f2;
}
tbody tr:hover {
  background: #f0f0f2;
}
td {
  padding: 15px 15px;
}
td:first-child {
}


.pagination {
    margin-top: 25px;
}
.pagination span {
  cursor: pointer;
  color: black;
  float: left;
  padding: 8px 16px;
  text-decoration: none;
  transition: background-color .3s;
  border: 1px solid #ddd;
}

.pagination span.active {
  background-color: #0099FF;
  color: white;
  border: 1px solid #0099FF;
}

pagination_app.module.css

Sorry for the plenty code written so far :), I want us to have a good looking table with pagination style in place before we move into the actual paging. If everything goes well, your view should look like below:

Pagination Data Format

In most cases, when you are making API calls to an endpoint that returns a paginated data, you need to pass at least the page number with the URL, hence a sample URL will look like below:

https://reqres.in/api/users?page=2

The most important thing to take note of in the URL above is the page=2 where 2 is the page number dataset we want to get. It can be 3,4 or any number as much as the dataset we have in the backend.

The response will always contain three important data which are per_page, total and the actual data we want to loop through. A sample response looks like below:

Sample API request

Talking about making an API request to the backend, We need a backend to make the request to, I decide to use https://reqres.in/ as the API endpoint for this tutorial because it is free, always available and reliable. You can decide to make your API request directly inside your component’s ComponentDidMount() or dispatch an action to redux from your ComponentDidMount() but for the purpose of this tutorial, we are going to make the API call from the App.js componentDidMount().

Firstly, we need to set the component’s state like below inside your App.js

  state = {
    users: null,
    total: null,
    per_page: null,
    current_page: null
  }

pagination_component_state.js

users is going to be the data we are going to loop over, while total and per_page is going to help us with calculating paging logic while the current_page will be used to style the active pagination link.

The next thing we should do is create a helper method that will serve the purpose of making an HTTP request to the API endpoint and also update the state with the response data. The method will look like below:

  makeHttpRequestWithPage = async pageNumber => {
    let response = await fetch(`https://reqres.in/api/users?page=${pageNumber}`, {
      method: 'GET',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

    const data = await response.json();

    this.setState({
      users: data.data,
      total: data.total,
      per_page: data.per_page,
      current_page: data.page,
    });
  }

pagination_http_request.js

This method will accept a parameter called pageNumber so it can be reusable and will always update the state with the right data when the response is successful.

Since on page load, we need to make the HTTP request to the backend, and we are going to do this inside thecomponentDidMount() by calling the method above and passing it the first-page number we want which should be 1. Hence, the componentDidMount() will look like below:

 componentDidMount() {
    this.makeHttpRequestWithPage(1);
  }

pagination_componentDidMount.js

If we add console.dir(this.state.users) inside the render() method, below will be printed in the console

The null was before the data arrived, once the data arrived, it updates the state, hence the array of users data.

Displaying the initial data

Haven gotten the data needed, we need to loop through the data and display it. Hence we can update our render method to have below:

    let users;

    if (this.state.users !== null) {
      users = this.state.users.map(user => (
        <tr key={user.id}>
          <td>{user.id}</td>
          <td>{user.first_name}</td>
          <td>{user.last_name}</td>
        </tr>
      )); 
    }
    
    return (
      <div className={styles.app}>
        
        <table className={styles.table}>
          <thead>
            <tr>
              <th>S/N</th>
              <th>First Name</th>
              <th>Last Name</th>
            </tr>
          </thead>
          <tbody>
              { users }
          </tbody>
        </table>


        <div className={styles.pagination}>
          <span>&laquo;</span>
          <span className={styles.active}>1</span>
          <span>2</span>
          <span>3</span>
          <span>4</span>
          <span>&raquo;</span>
        </div>

      </div>
    );

gistfile1.txt

I replaced the dummy data we had inside the with the result of the loop which I equated to users. We have the assurance that when the state changes, ReactJs will automatically update the content of the table. The final stage is displaying the page logic and getting the other contents based on the page number clicked which will be sent to the API endpoint.

Showing Page Number and getting other data

Before we talk about showing page number automatically using the desired logic, I want us to manually show those numbers and make the actual API calls when the numbers are clicked. For now, we are going to hard code the pagination numbers ourselves like below:

<div className={styles.pagination}>
  <span onClick={() => this.makeHttpRequestWithPage(1)}>1</span>
  <span onClick={() => this.makeHttpRequestWithPage(2)}>2</span>
  <span onClick={() => this.makeHttpRequestWithPage(3)}>3</span>
  <span onClick={() => this.makeHttpRequestWithPage(4)}>4</span>
</div>

pagination_hard_code.js

The above code will look like below when previewed in the browser.

Notice that each span has an event handler attached to it, and I passed the page number to that event handler, so anytime we click on the pagination link, it will make a new HTTP request and update the component states, hence the user’s table data. We do not want to hard-code the links as we did above, so we need to automatically display those links.

So we’re planning on showing the page numbers for a series of pieces of data so that users can easily navigate multiple items. There are a few things that we need to know first:

  • The page that we’re on
  • Total number of items
  • Number of items per page

Good news is that we have captured all these things in our component’s state.

Next, we need to look at how we want to display the page numbers, there is a wide range of methods that people use:

  • Simple Next/Previous buttons with no numbers
  • A list of all possible pages
  • Page 1 & the last page, with the current page (and 2 above/below) shown

I personally prefer to show the very first page, that last page, and then the current page with 2 pages above & below. So for example on page 12 out of 24 pages we’d see:

1, 10, 11, 12, 13, 14, 24

This allows users to quickly navigate to the start, and to the end, as well as jump through multiple pages at once. For the purpose of this tutorial, I am going to show us how to show a list of all possible pages(item two above) then item three too.

The Arithmetic

We need to work out the total number of pages, for this, we want to take the total number of items that there are, and divide it by the number of items per page. But we want to make sure that we take that number and round it up.

So if there were 12 items in total, and we were showing 5 per page, we’d have a total of 3 pages of items. If we were to show 3 per page, we’d show 4 pages.

const pageNumbers = [];
for (let i = 1; i <= Math.ceil(this.state.meta.total / this.state.meta.per_page); i++) {
    pageNumbers.push(i);
}

page_logic_pagination.js

Haven gotten the page numbers, we need to loop through to display the span since we want to show all possible numbers first, our loop will look like below:

renderPageNumbers = pageNumbers.map(number => {
  let classes = this.state.current_page === number ? styles.active : '';

  return (
    <span key={number} className={classes} onClick={() => this.makeHttpRequestWithPage(number)}>{number}</span>
  );
});

pagination_all_numbers_loop.js

We need to update our pagination view to look like below:

<div className={styles.pagination}>
  <span onClick={() => this.makeHttpRequestWithPage(1)}>&laquo;</span>
  {renderPageNumbers}
</div>

pagination_view._01js

Congrats, we have successfully handle pagination, make HTTP request to the backend and changing the table content when user click on the page number to see.

To be sure we are on the same page, my App.js code looks like below:

import React, { Component } from 'react';
import styles from './App.module.css';

class App extends Component {


  state = {
    users: null,
    total: null,
    per_page: null,
    current_page: 1
  }


  componentDidMount() {
    this.makeHttpRequestWithPage(1);
  }


  makeHttpRequestWithPage = async pageNumber => {
    const response = await fetch(`https://reqres.in/api/users?page=${pageNumber}`, {
      method: 'GET',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json',
      },
    });

    const data = await response.json();

    this.setState({
      users: data.data,
      total: data.total,
      per_page: data.per_page,
      current_page: data.page
    });
  }


  render() {

    let users, renderPageNumbers;

    if (this.state.users !== null) {
      users = this.state.users.map(user => (
        <tr key={user.id}>
          <td>{user.id}</td>
          <td>{user.first_name}</td>
          <td>{user.last_name}</td>
        </tr>
      ));
    }

    const pageNumbers = [];
    if (this.state.total !== null) {
      for (let i = 1; i <= Math.ceil(this.state.total / this.state.per_page); i++) {
        pageNumbers.push(i);
      }


      renderPageNumbers = pageNumbers.map(number => {
        let classes = this.state.current_page === number ? styles.active : '';

        return (
          <span key={number} className={classes} onClick={() => this.makeHttpRequestWithPage(number)}>{number}</span>
        );
      });
    }

    return (


      <div className={styles.app}>

        <table className={styles.table}>
          <thead>
            <tr>
              <th>S/N</th>
              <th>First Name</th>
              <th>Last Name</th>
            </tr>
          </thead>
          <tbody>
            {users}
          </tbody>
        </table>


        <div className={styles.pagination}>
          <span onClick={() => this.makeHttpRequestWithPage(1)}>&laquo;</span>
          {renderPageNumbers}
          <span onClick={() => this.makeHttpRequestWithPage(1)}>&raquo;</span>
        </div>

      </div>
    );
  }

}

export default App;

pagination_app.js

and my view like below:

We can change the page number display logic to below since it will accommodate for large dataset.

renderPageNumbers = pageNumbers.map(number => {
  let classes = this.state.current_page === number ? styles.active : '';

  if (number == 1 || number == this.state.total || (number >= this.state.current_page - 2 && number <= this.state.current_page + 2)) {
    return (
      <span key={number} className={classes} onClick={() => this.makeHttpRequestWithPage(number)}>{number}</span>
    );
  }
});

pagination_another_display_logic.js

Thanks for reading.

URLs and Webpack in Reactjs

URLs and Webpack in Reactjs

URLs and Webpack in Reactjs - I am still a newbie in ReactJS. I've been following series of tutorials and articles on the framework and decided to start putting what I've learnt so far into practice.

My website, dillionmegida.com was built with PHP. You could check it out as I highly appreciate reviews. I'm though aspiring to be a full-stack javascript developer so I'm in some way trying to depart from PHP :)

I decided to replicate my homepage using React and to broaden my skills in using components.

It was going quite successful until I tried using an <img> JSX element. I used it like;

import React from 'react'
 
let dpStyle = {
    // Some styles
}
 
let Profilepic = () => (
    <div className={dpStyle}>
        <img src='../img/deee.jpeg' alt='My profile picture'/>
    </div>
)
export default Profilepic;

The img folder was a sub-directory of the src folder.

My aim here was to have my profile picture as a component with some styling to be used on my homepage and any other desired page. The src for the img tag was not been used appropriately as my image was not displayed.

I paused to think of the problem, inspected my page and discovered the src displayed there was exactly as I inputted it. So silly of me :( I made some researches which helped me remember that most attributes of JSX element are not as mostly used with HTML, but have to be enclosed in curly braces.

import React from 'react'
 
let dpStyle = {
    // Some styles
}
 
let Profilepic = () => (
    <div className={dpStyle}>
        <img src={'../img/deee.jpeg'} alt='My profile picture'/>
    </div>
)
export default Profilepic;

I tried rendering the page again and my image was still not displayed.

Funny enough, I quickly thought of a trick (for the first time);

...
import Dp from '../img/deee.jpeg'
...
let Profilepic = () => (
    <div className={dpStyle}>
        <img src={Dp} alt='My profile picture'/>
    </div>
)

To my amazement, it worked. I was excited and at the same time sad, with feeling of little guilt. I didn't know why. lol. I said to myself, 'I am not doing the right thing :(' and also asked myself, 'Is react as crazy as this?'

I headed back to google to make some more research and got to discover that the webpack that React (create-react-app) automatically installed had been configured to use the public folder (at the same level with src folder) for relative URLs (such as my image URL).

Using ...<img src={'../img/deee.jpeg'} />..., React was actually checking the public folder for the image sub-directory which it couldn't find.

Solution

1. Change the location of the image folder

I changed the location of the image folder making it a sub-directory under the public directory and it worked as expected.

2. Use the require keyword

Just as the import keyword is used for relative URLs, the require keyword does same. So, I was able to do this;

import React from 'react'
 
let dpStyle = {
    // Some styles
}
 
let Profilepic = () => (
    <div className={dpStyle}>
        <img src={require('../img/deee.jpeg')} alt='My profile picture'/>
    </div>
)
export default Profilepic;

and in the other pages where the Profilepic component was required and used, my image displayed perfectly. :D

Like I said, I am still a newbie at ReactJS but I hope this little experience would be helpful for you too. There are other super powers of webpacks too which I would still be learning. Please do share in the comment section corrections on this article and also helpful Tips.

I'll be documenting my experience in my ReactJS journey as much as I can. Stay tuned and thanks for reading.

Originally published by Megida Dillion at dillion.hashnode.dev

=======================================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

Learn More

☞ Understanding TypeScript

☞ Typescript Masterclass & FREE E-Book

☞ React - The Complete Guide (incl Hooks, React Router, Redux)

☞ Modern React with Redux [2019 Update]

☞ The Complete React Developer Course (w/ Hooks and Redux)

☞ React JS Web Development - The Essentials Bootcamp

☞ React JS, Angular & Vue JS - Quickstart & Comparison

☞ The Complete React Js & Redux Course - Build Modern Web Apps

☞ React JS and Redux Bootcamp - Master React Web Development