Creating a Modern Application: Using Laravel With React.js

by Farhan Hasin Chowdhury

12 min read·

I started my web development career as a Python programmer, and my go-to framework in those days was Django. I came across Laravel only 1.5 years into my career and started building stuff using the framework. Eventually, I got better at Laravel and reached a point where I would choose between the frameworks depending on requirements.

For example, if I saw that a project has pages that require something to happen in real-time, I would immediately choose Laravel over Django. Back in the day, Laravel used to come with Vue pre-installed and pre-configured with every new project.

Laravel has come a long way, and the options for creating modern, reactive web applications using the framework are many. There's Inertia.js, Alpine.js, Livewire, and more. But the framework hasn't said goodbye to the old ways of doing things. It's still possible and very straightforward to set up Vue or React with a Laravel project.

In this article, I'll walk you through the process of bootstrapping a brand new Laravel project and integrating React with it so all Laravel developers, as well as React.js developers out there, can proceed with the project safely.

I'll use Laravel 8 throughout the article (one of the reasons being the excellent Laravel security features of the version), but you should be able to follow along with future versions of the framework as well. The article assumes that you have experience working with both Laravel and ReactJs.

Bootstrapping a New Project and Installing the Dependencies

Let's start by creating a new Laravel project anywhere on your local computer. You can use whatever method of bootstrapping you may like. I prefer using the Laravel Installer in this case.

laravel new guide-to-laravel-and-react

Once the project is ready, open it in your favorite IDE or text editor. If you look inside the package.json file present in every new Laravel project, you'll see the following list of packages under the devDependencies section:

  • axios - promise-based HTTP client
  • laravel-mix - an elegant wrapper over webpack
  • lodash - popular functional programming library
  • postcss - utility tool for automating routine CSS operations

In this article, you'll be working with all of these libraries except for Lodash.

Now that you know about all these dependencies, let's go ahead and install them:

npm install

After the installation finishes, execute the following command to test if everything's functional or not.

npm run dev

If everything works fine, you should see something as follows on your terminal:

Laravel and React

Let me explain what just happened.

When you executed the npm run dev command, Laravel Mix compiled the resources/js/app.js file and the resources/css/app.css file into public/js/app.js and public/css/app.css files.

Installing React and Writing Your First Component

Let's go ahead and start bringing React into the scene to see the whole process of using Laravel with React.js. First, you'll have to install two new JavaScript libraries. They are the react and react-dom libraries. To do so, execute the following command:

npm install --save-dev react react-dom

It'll install the libraries as development dependencies. The reason behind installing them as development dependencies is that you'll compile all your JavaScript code into a single file and attach that with your Blade templates.

Create a new file resources/js/components/HelloReact.js and put the following content in there:

// resources/js/components/HelloReact.js

import React from 'react';
import ReactDOM from 'react-dom';

export default function HelloReact() {
    return (
        <h1>Hello React!</h1>
    );
}

if (document.getElementById('hello-react')) {
    ReactDOM.render(<HelloReact />, document.getElementById('hello-react'));
}

It's a functional React component that mounts on any element with the id "hello-react" and prints "Hello React!" on the page. To make this usable throughout your entire application, you'll have to include this in your JavaScript code bundle. To do so, open the resoureces/js/app.js file and update its code as follows:

// resoureces/js/app.js

require('./bootstrap');

// React Components
require('./components/HelloReact')

And that's it. Requiring the React component in this file will include it in the application's JavaScript code bundle. Before you can use this updated code in your blade templates, you'll have to recompile it.

Previously you were writing only vanilla JavaScript in your code, but now you're writing React-related code. You'll have to change the Laravel Mix configuration so that it can compile the React component properly. To do so, open the webpack.mix.js file from the project root and update its code as follows:

// webpack.mix.js

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
    .react()
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

By default, the configuration file doesn't call the react() function. Calling this function will tell Laravel Mix to install the babel-preset-react plugin required for compiling React components. 

After updating the Laravel Mix configuration, execute the npm run dev command once again. Keep in mind that the compilation will not happen this time. Instead, Laravel Mix will realize some libraries are missing and install them. So run the npm run dev command once again, and this time the execution should succeed.

Now that the component is ready to use, you'll have to prepare a blade template. Open the resources/views/welcome.blade.php file and update its content as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Laravel React</title>

    <script src="{{ asset('js/app.js') }}" defer></script>
</head>
<body>
    <div id="hello-react"></div>
</body>
</html>

Make sure that you defer the script execution or put it just before the body tag ends. Also, make sure to match the element ID with the ID you wrote in the React component's render() function. 

Now start the development server by executing php artisan serve and visit http://localhost:8000 using your favorite browser. You should see something as follows:

how to use Laravel with React

If you see nothing on the screen, check the browser console for any errors. If you find something, resolve them and try again.

Creating a Counter Component Using React Hooks

Let's write a counter component using the state hook. Create a file resources/js/Counter.js and put the following content in it:

// resources/js/components/Counter.js

import React, { useState } from "react";
import ReactDOM from 'react-dom';

export default function Counter() {
  // Set the initial count state to zero, 0
  const [count, setCount] = useState(0);

  // Create handleIncrement event handler
  const handleIncrement = () => {
    setCount(prevCount => prevCount + 1);
  };

  // Create handleDecrement event handler
  const handleDecrement = () => {
    setCount(prevCount => prevCount - 1);
  };
  return (
    <div>
        <button onClick={handleDecrement}>-</button>
        <span> {count} </span>
        <button onClick={handleIncrement}>+</button>
    </div>
  );
}

if (document.getElementById('counter')) {
    ReactDOM.render(<Counter />, document.getElementById('counter'));
}

if (document.getElementById('counter')) {
    ReactDOM.render(<Counter />, document.getElementById('counter'));
}

Open the resources/js/app.js file and require it just like the previous one. Instead of executing the npm run dev command, again and again, you can execute the npm run watch command, which keeps an eye on your files and compiles them automatically on change.

Finally, open the resources/views/welcome.blade.php file one more time and update its content as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Laravel React</title>

    <script src="{{ asset('js/app.js') }}" defer></script>
</head>
<body>
    <div id="hello-react"></div>
    <div id="counter"></div>
</body>
</html>

Refresh the page if it's still open in your browser, and you should see something as follows:

using Laravel with React.js

Try hitting the increment and decrement button, and you will see the number change. Anything you can do in a regular React component, you can do here. Even if you want to write class components, go ahead.

Communicating With the Back-End

So far in this article, you've only worked in the front-end. In this section, I'll show you how you may communicate with the Laravel back-end from your React components.

To do so, open the routes/web.php file and update its content as follows:

<?php

// routes/web.php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    return view('welcome');
});

Route::post('count', function (Request $request) {
    return response()->json([
        'message' => $request->message,
    ]);
});

I won't overcomplicate things by introducing databases and stuff. This simple route receives a string named message from the front-end and sends it back.

Open the resources/js/Counter.js file and update its content as follows:

// resources/js/Counter.js

import axios from "axios";
import React, { useState } from "react";
import ReactDOM from 'react-dom';

export default function Counter() {
  // Set the initial count state to zero, 0
  const [count, setCount] = useState(0);

  // Create handleIncrement event handler
  const handleIncrement = () => {
    setCount(prevCount => prevCount + 1);
    notifyServer();
  };

  // Create handleDecrement event handler
  const handleDecrement = () => {
    setCount(prevCount => prevCount - 1);
    notifyServer();
  };

  // Notifies the server about the change
  const notifyServer = () => {
      axios.post('/count', {
          message: 'Counter Updated!',
      })
  }

  return (
    <div>
        <button onClick={handleDecrement}>-</button>
        <span> {count} </span>
        <button onClick={handleIncrement}>+</button>
    </div>
  );
}

if (document.getElementById('counter')) {
    ReactDOM.render(<Counter />, document.getElementById('counter'));
}

The notifyServer() function sends a POST request to the /count endpoint with a message. Make sure to call it inside both the handleDecrement() and handleIncrement() functions. Recompile the assets and refresh the page. Now, before pressing the increment or decrement buttons, open the network tab in your browser. Now press the increment or the decrement button, and a POST request will show up as follows:

Laravel and React tutorial

As you can see, the server has received the request and responded with the message. You can send any request to the server this way. The Axios library also handles the CSRF token by sending the XSRF-TOKEN cookie with every request, so you should be able to connect to any of the web routes.

You can also use API routes here, but then, you'll have to implement a stateless authentication system. In my opinion, if you're using React components within blade templates, work with web routes. It'll give you much less hassle and allow you to do almost anything that the API routes allow you to do.

Vendor Extraction

The last topic that I would like to discuss in this article is vendor extraction. One downside of bundling up your application-centric JavaScript code and the React library together is that it makes long-term caching difficult. A single change in your code will force the browser to re-download the vendor library i.e. React even though they haven't changed.

One way to solve this issue is by extracting the vendor library code in a separate file. To do so, open the webpack.mix.js file and update its code as follows:

// webpack.mix.js

const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js')
    .react()
    .extract(['react'])
    .postCss('resources/css/app.css', 'public/css', [
        //
    ]);

The extract() function will extract any vendor library in the array and produce three separate JavaScript files. They are as follows:

  • public/js/manifest.js: The Webpack manifest runtime
  • public/js/vendor.js: Your vendor libraries
  • public/js/app.js: Your application code

Open the resources/views/welcome.blade.php file and update its content as follows:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Laravel React</title>
</head>
<body>
    <div id="hello-react"></div>
    <div id="counter"></div>

    <script src="{{ asset('js/manifest.js') }}"></script>
    <script src="{{ asset('js/vendor.js') }}"></script>
    <script src="{{ asset('js/app.js') }}"></script>
</body>
</html>

Instead of deferring code execution, I've moved the scripts to the bottom of the file. Also, make sure to load the files in this exact order. If there are multiple application-centric JavaScript files, they should come after the vendor script. The manifest will always be the first one. Reload your browser, and you should see no change in results whatsoever.

Conclusion

I would like to thank you for the time you've spent reading this article. I hope you've enjoyed it and have learned some valuable stuff from this article. If you're confused about any part of this article, feel free to browse the reference repository. I would also suggest you read through the official Laravel docs on Compiling Assets (Mix) to learn about concepts such as cache busting, environment variables, and more.


If you have any questions, feel free to reach out to me. I'm available on Twitter and LinkedIn and always happy to help. Till the next one, stay safe and keep on learning.

FAQs

Q: Can I use React JS with Laravel?
Laravel doesn't require you to use any specific Javascript framework. As long as you've configured Laravel Mix properly, any framework should work.
Q: What is React and Laravel?
React is an open-source frontend Javascript library developed by Facebook and Laravel is a full-stack PHP framework following the MVC pattern.
Q: How does Reactjs integrate with Laravel?
The integration is pretty seamless. All you have to do is call the react() function in the Laravel Mix configuration and put your components within the correct directory. 

We're hiring!

If you are passionate about Laravel, come and join us at Adeva! We are always looking for new talent to join our network.