DEV Community

Cover image for How to use React to Send a POST Request to a Laravel Application
Terrence Aluda
Terrence Aluda

Posted on

How to use React to Send a POST Request to a Laravel Application

Perhaps you are a backend engineer who wants to load data to your site using the React library, or you want to explore the use of React with Laravel. Or maybe you have other interests in using Laravel with React, either way you are at the right place.

We are going to learn how to make a POST request to a Laravel application using React and retrieve the response.

Basic descriptions

  • React: This is a JavaScript library that assists us in creating interactive and dynamic Single Page Applications.
  • Axios: This is a library that is used to handle HTTP requests to external sources in web applications.
  • Laravel: This is a PHP framework based on the Model-View-Controller architecture that helps us create web backend applications faster.

Prerequisites

  • A basic understanding of PHP and how to work with Laravel.
  • A basic understanding of HTML and CSS.
  • A basic understanding of JavaScript and how to use on React.
  • Have PHP, Composer, and Laravel installer installed in your machine.

Having that, we can now start diving into the topic.

What we will be doing

We will be sending input data from a sign up page and send the data to a Laravel controller which will, in turn, return JSON data and display it in an alert.

JSON, JavaScript Object Notation; is a data exchange format between web applications.

Getting started

We create our application by running this command in the terminal:

laravel new reactaxios
Enter fullscreen mode Exit fullscreen mode

Since Laravel supports Vue.js by default, we first have to replace the Vue.js scaffolding with React.js.

php artisan preset react
Enter fullscreen mode Exit fullscreen mode

Creating the Controller and the Route

We then create the controller of our Laravel application receiving the POST request.

php artisan make:controller AxiosReceiverController
Enter fullscreen mode Exit fullscreen mode

Open the controller and add the following code.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class AxiosReceiverController extends Controller
{
    public function ReceiveIt(Request $request){
        $validatedData = $request->validate([
            'firstname' => 'nullable',
            'lastname' => 'nullable',
            'email' => 'nullable',
            'phone' => 'nullable',
            'NatID' => 'nullable',
            'password' => 'nullable',
            'userLevel' => 'nullable'
        ]);

        return json_encode($validatedData);
    }
}
Enter fullscreen mode Exit fullscreen mode

The controller contains a method ReceiveIt() which receives a request, validates it according to the user rules then stores it in an array named $validatedData. It then returns the array as a JSON object which we'll retrieve later on.

We then head on to create a Route for the controller in the routes/web.php file.

Route::post('sendrequest', 'App\Http\Controllers\AxiosReceiverController@ReceiveIt');
Enter fullscreen mode Exit fullscreen mode

Building the React and Frontend module

We add our application's dependencies.

npm install
Enter fullscreen mode Exit fullscreen mode

To handle our routes, we will use the React Router where we render a single view for all the routes. This is particularly important if you have many routes. For our case, it will only be one route.

We will create a wildcard route in the routes/web where a view file app.blade.php will be used to render our React components. Replace the view code in the routes/web with the code below.

Route::view('/{path?}', 'app');
Enter fullscreen mode Exit fullscreen mode

We head on to the resources/views directory, create the file app.blade.php and add the following code:

<!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <!-- CSRF Token -->
        <title>ReactAxios</title>
        <!-- Styles -->
        <link href="{{ asset('css/app.css') }}" rel="stylesheet">
    </head>
    <body>
        <div id="app"></div>

        <script src="{{ asset('js/app.js') }}"></script>
    </body>
    </html>
Enter fullscreen mode Exit fullscreen mode

We reference both a CSS and a JavaScript file that contain React and other dependencies. We have an empty div with an id of "app" where our components will be rendered.

Next, we create the App component in the resources/js/components with the name App.jsx and delete the Example.js that is there by default.

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import './App.css';

class App extends Component {
  render () {
    return (
      <BrowserRouter>
        <div>
          <Switch>

          </Switch>
        </div>
      </BrowserRouter>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))
Enter fullscreen mode Exit fullscreen mode

We will install React router since we are using it:

npm install react-router-dom
Enter fullscreen mode Exit fullscreen mode

While the installation continues, open the app.js file in the resources/js/ directly and update the code found there with this one:

    require('./bootstrap')
    require('./components/App')
Enter fullscreen mode Exit fullscreen mode

The Signup page

We will create a folder called pages in the resources/js/components/ directory where we will create the signup page, name it Register.jsx, and add it to the folder. Add the following code inside it.

import React, { Component } from 'react';
import axios from "axios";
import wave from 'https://terrence-aluda.com/wave.png'
import bg from 'https://terrence-aluda.com/bg.svg'
import avatar from 'https://terrence-aluda.com/avatar.svg'

class Register extends Component {

    constructor(props){
        super(props);

        this.state = {
            firstname : '',
            lastname : '',
            email : '',
            phone : '',
            NatID : '',
            password : '',
            userLevel : 'Job Expert'
        }

        this.firstName = this.firstName.bind(this);
        this.lastName = this.lastName.bind(this);
        this.takePhone = this.takePhone.bind(this);
        this.takeEmail = this.takeEmail.bind(this);
        this.takeID = this.takeID.bind(this);
        this.takePassword = this.takePassword.bind(this);
        this.takeLevel = this.takeLevel.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    firstName(event){
        this.setState({firstname : event.target.value})
    }
    lastName(event){
        this.setState({lastname : event.target.value})
    }
    takePhone(event){
        this.setState({phone : event.target.value})
    }
    takeEmail(event){
        this.setState({email : event.target.value})
    }
    takeID(event){
        this.setState({ID : event.target.value})
    }
    takePassword(event){
        this.setState({password : event.target.value})
    }
    takeLevel(event){
        this.setState({userLevel : event.target.value})
    }

    handleSubmit(){

        const packets = {
            firstname:  this.state.firstname,
            lastname: this.state.lastname,
            email: this.state.email,
            phone: this.state.phone,
            NatID: this.state.ID,
            userLevel: this.state.userLevel,
            password: this.state.password
        };
        axios.post('/sendrequest', packets)
            .then(
                response => alert(JSON.stringify(response.data))

                )
            .catch(error => {
                console.log("ERROR:: ",error.response.data);

                });
    }

    render(){
        return (
<div>

            <img class="wave" src={wave} alt="img"/>
            <div class="container">
                <div class="img">
                    <img src={bg} alt="img"/>
                </div>
                <div class="login-content">
                    <form>
                        <img src={avatar} alt="img"/>
                        <h2 class="title">Register</h2>
                           <div class="input-div one">
                              <div class="i">
                                      <i class="fas fa-user"></i>
                              </div>
                              <div class="div">
                                      <h5></h5>
                                      <input type="text" placeholder="First Name" onChange={this.firstName} class="input"/>
                              </div>
                           </div>

                           <div class="input-div one">
                              <div class="i">
                                      <i class="fas fa-user"></i>
                              </div>
                              <div class="div">
                                      <h5></h5>
                                      <input type="text" placeholder="Last Name" onChange={this.lastName} class="input"/>
                              </div>
                           </div>

                           <div class="input-div pass">
                              <div class="i"> 
                                   <i class="fas fa-envelope-square"></i>
                              </div>
                              <div class="div">
                                   <h5></h5>
                                   <input type="email" placeholder="Email" onChange={this.takeEmail} class="input" />
                           </div>
                        </div>

                        <div class="input-div pass">
                              <div class="i"> 
                                   <i class=""></i>
                              </div>
                              <div class="div">
                              <select onChange={this.takeLevel} name="userLevel">
                                    <option value="">Choose level</option>                                 
                                    <option value="Job Expert">Job Expert</option>
                                    <option value="Client">Client</option>
                                </select>
                           </div>
                        </div>

                        <div class="input-div pass">
                              <div class="i"> 
                                   <i class="fas fa-id-card"></i>
                              </div>
                              <div class="div">
                                   <h5></h5>
                                   <input type="number" placeholder="National ID" onChange={this.takeID} class="input" />
                           </div>
                        </div>

                        <div class="input-div pass">
                              <div class="i"> 
                                   <i class="fas fa-phone"></i>
                              </div>
                              <div class="div">
                                   <h5></h5>
                                   <input type="number" placeholder="Phone Number" onChange={this.takePhone} class="input" />
                           </div>
                        </div>

                           <div class="input-div pass">
                              <div class="i"> 
                                   <i class="fas fa-lock"></i>
                              </div>
                              <div class="div">
                                   <h5></h5>
                                   <input type="password" placeholder="Password" onChange={this.takePassword} class="input" />
                           </div>
                        </div>

                        <div class="input-div pass">
                              <div class="i"> 
                                   <i class="fas fa-lock"></i>
                              </div>
                              <div class="div">
                                   <h5></h5>
                                   <input type="password" placeholder="Confirm Password" class="input" />
                           </div>
                        </div>
                        <input type="submit" class="btn" onClick={this.handleSubmit} value="Register"/>
                    </form>
                </div>
            </div>

                </div>
        );
    }
}
export default Register;
Enter fullscreen mode Exit fullscreen mode

Explanation

We reference the images we'll be using on the page.

The constructor then initializes state values and binds the component's functions.

The succeeding functions are used to take values from the inputs they are called from after a user types them in, then sets the state values appropriately.

The handleSubmit() function is called when the submit button is clicked. The function contains an object called packets with properties from the state object. This is then passed in the Axios post method as a request to the Laravel controller route we created.

After the request, we retrieve the results and display it in an alert using the JSON.stringify() method which converts the object returned to a string. If there is an error during the process, it is shown in the console after being 'caught'.

Adding the styling for the page and updating the App.jsx file

For the styling, you can customize and add your own but what we will be using to format our page, is in the CSS code below.

Open resources/js/components/App.css and add this code:

@import url('https://fonts.googleapis.com/css2?family=Nunito:wght@200&family=Roboto:wght@100&display=swap');

:root{
  --nav-width: 68px;

  /* colors */
  --first-color: #00BFA6/*#472347D9*/;
  --first-color-light: #fff/*#AFA5D9*/;
  --white-color: #F7F6FB;

  /* === Font and Typography */
  --body-font: 'Nunito', sans-serif;
  --normal-font-size: 1rem;
  /* z-index */
  --z-fixed: 100;
}

body{
  font-family: Nunito, sans-serif;
  position: relative;
  /* margin: var(--header-height) 0 0 0; */
  margin: 0;
  padding: 0;
  font-family: var(--body-font);
  font-size: var(--normal-font-size);
  transition: .5s;
}

*, ::before, ::after{
  box-sizing: border-box;
}

body::-webkit-scrollbar{
  width: 8px;
}

body::-webkit-scrollbar-thumb{
  background-color: rgb(36, 36, 36);
}
body::-webkit-scrollbar-track{
  background-color: rgb(235, 236, 235);
}

.login-register{
  display: flex;
  justify-content: space-between;
}
.login-register a{
  margin-right: 6px;
}
a{
  text-decoration: none;
}

form {
  background: white;
  border: 1px solid #dedede;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  margin: 0 auto;
  max-width: 500px;
  padding: 30px 50px;
}
button{
  border: none;
  border-radius: 5px;
}


input,select {
  border: 1px solid #d9d9d9;
  border-radius: 4px;
  box-sizing: border-box;
  padding: 10px;
  width: 100%;
}

label {
  color: #3d3d3d;
  display: block;
  font-family: sans-serif;
  font-size: 14px;
  font-weight: 500;
  margin-bottom: 5px;
}

li{
  list-style: none;
  margin: 0 10px;
}


/**Login**/

.wave{
  position: fixed;
  bottom: 0;
  left: 0;
  height: 100%;
  z-index: -1;
}

.container{
    width: 100vw;
    height: 100vh;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    grid-gap :7rem;
    padding: 0 2rem;
}

.img{
  display: flex;
  justify-content: flex-end;
  align-items: center;
}

.login-content{
  display: flex;
  justify-content: flex-start;
  align-items: center;
  text-align: center;
}

.img img{
  width: 500px;
}

form{
  width: 360px;
}

.login-content img{
    height: 100px;
}

.login-content h2{
  margin: 15px 0;
  color: #333;
  text-transform: uppercase;
  font-size: 2.9rem;
}

.login-content .input-div{
  position: relative;
    display: grid;
    grid-template-columns: 7% 93%;
    margin: 25px 0;
    padding: 5px 0;
    border-bottom: 2px solid #d9d9d9;
}

.login-content .input-div.one{
  margin-top: 0;
}

.i{
  color: #d9d9d9;
  display: flex;
  justify-content: center;
  align-items: center;
}

.i i{
  transition: .3s;
}

.input-div > div{
    position: relative;
  height: 45px;
}

.input-div > div > h5{
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  color: #999;
  font-size: 18px;
  transition: .3s;
}

.input-div:before, .input-div:after{
  content: '';
  position: absolute;
  bottom: -2px;
  width: 0%;
  height: 2px;
  background-color: #38d39f;
  transition: .4s;
}

.input-div:before{
  right: 50%;
}

.input-div:after{
  left: 50%;
}

.input-div.focus:before, .input-div.focus:after{
  width: 50%;
}

.input-div.focus > div > h5{
  top: -5px;
  font-size: 15px;
}

.input-div.focus > .i > i{
  color: #38d39f;
}

.input-div > div > input{
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  border: none;
  outline: none;
  background: none;
  padding: 0.5rem 0.7rem;
  font-size: 1.2rem;
  color: #555;
  font-family: 'poppins', sans-serif;
}

.input-div.pass{
  margin-bottom: 4px;
}

a{
  display: block;
  text-align: right;
  text-decoration: none;
  color: #999;
  font-size: 0.9rem;
  transition: .3s;
}

a:hover{
  color: #38d39f;
}

.btn{
  display: block;
  width: 100%;
  height: 50px;
  border-radius: 10px;
  outline: none;
  border: none;
  background-image: linear-gradient(to right, #32be8f, #38d39f, #32be8f);
  background-size: 200%;
  font-size: 1.2rem;
  color: #fff;
  font-family: 'Poppins', sans-serif;
  text-transform: uppercase;
  margin: 1rem 0;
  cursor: pointer;
  transition: .5s;
}
.btn:hover{
  background-position: right;
}


@media screen and (max-width: 1050px){
  .container{
    grid-gap: 5rem;
  }
}

@media screen and (max-width: 1000px){
  form{
    width: 290px;
  }

  .login-content h2{
        font-size: 2.4rem;
        margin: 8px 0;
  }

  .img img{
    width: 400px;
  }
}

@media screen and (max-width: 900px){
  .container{
    grid-template-columns: 1fr;
  }

  .img{
    display: none;
  }

  .wave{
    display: none;
  }

  .login-content{
    justify-content: center;
  }
}

/**fire**/
.fa-fire{
  color: rgb(255,102,102);
  font-size: 3.8rem;
}

footer{
  font-size: 1.5rem;
  padding: 0.8rem;
  text-align: center;
  background-color: rgb(20, 20, 20);
  color:#F7F6FB;
  }

.dash{
  background-color:#f2f4f6;
  min-width: 60vw;
  display: flex;
  justify-content: center;
  align-items: center;
}

.card-header{
  background-color: #32be8f;
  color: #fff;
}

.list-group-flush li:first-child{
  font-size: 1.8rem;
  color: blue;
  text-decoration: underline;
}

.list-group-flush li:nth-child(2){
  color: #6026ff;
  font-size: 1.1rem;
  font-weight: 500;
}

.list-group-flush{
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: center;
}

Enter fullscreen mode Exit fullscreen mode

We update the App.jsx file with the routes to display with this code snippet:

import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { BrowserRouter, Route, Switch } from 'react-router-dom'
import './App.css';
import RegisterPage from './pages/Register';

class App extends Component {
  render () {
    return (
      <BrowserRouter>
        <div>
          <Switch>
            <Route exact path='/' component={RegisterPage} />     
          </Switch>
        </div>
      </BrowserRouter>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('app'))
Enter fullscreen mode Exit fullscreen mode

Running the app

Before running the app, we first need to test-compile the react using Laravel Mix by running this command:

npm run dev
Enter fullscreen mode Exit fullscreen mode

Then run the Laravel server:

php artisan serve
Enter fullscreen mode Exit fullscreen mode

The expected output:

First Screenshot

Second Screenshot

Third Screenshot

Conclusion

In this tutorial we got an overview on using the Axios library to send a HTTP request. A POST request which is used in making our applications RESTful. We saw the use of JSON in passing information between the backend and frontend. I will talk about other HTTP methods using these technologies in other tutorials.

That's all for now. Hope you've gotten insights on how to make a POST request from React using Axios to a Laravel application.

Have a good one!

Happy coding.

Top comments (0)