Laravel + React
Tags: tutorial, laravel, react
Published: 2020-10-16 22:53:18

---
title: Laravel + React
published: true
date: 2020-10-16 19:43:26 UTC
tags: Tutorial,Laravel,React
canonical_url: https://joeczubiak.com/laravel-plus-react/
cover_image: https://dev-to-uploads.s3.amazonaws.com/i/ftfj1f0zmz87j5pqlaxj.png
---

This tutorial will show you how to use React with Laravel in a way that lets you sprinkle React into a legacy Laravel codebase and blade templates. We will not be creating an SPA or using Create React App.

**You can view and download the full sample project.**

[https://github.com/jcz530/laravel-plus-react](https://github.com/jcz530/laravel-plus-react)

### After going through this guide...
- We'll be able to add React components into blade files.
- We'll have reusable components that can be combined to make complex components.
- We'll use webpack (Laravel Mix) to build our files.
- We **will not** have an SPA.
- React **will not** be served with SSR (Server Side Rendering).
- We **will not** be able to use the components as inline components like is popular with Vue.    

###   Background

I was inspired to write this guide because recently, I added React into a legacy project of mine, and I didn't want to rewrite the whole project to turn it into a React SPA. Instead, I wanted to reap the benefits of writing new React components that I could start sprinkling into my project right away.

There are a lot of ways to get React to load and render components, and this is simply the method I choose when working on my project. I'll walk you through how and why I chose this setup.

First thing's first, navigate to your existing or new Laravel project.

## Install Dependencies

`npm i react react-dom`

## Folder Structure

In the `/resources/js/` folder, we'll add a new folder where all of our React files will live. We want to keep these files all together and not mixed in with other JS files. This will keep the project organized, make some of the webpack setup easier, and allow for the use of other technologies.

In my case, I created a source folder for all of my React files at `/resources/js/src/`.

I have the following folders in the `src` folder.

- /src/components
- /src/hooks
- /src/layouts
- /src/pages    


Your exact folders may vary depending on your needs and organizational style, but this could be a good place to start.

## Laravel Mix - Webpack setup

### Aliases

This step is optional, but I think it makes the project a lot easier and cleaner to work with. Defining aliases in the webpack configs will allow you to refer to your files without needing to know where in the file path you are.

For example, if you want to refer to your theme file from a component deep in the folder structure, without aliases, you might write

`import theme from '../../../themes/theme.js'`

With aliases, you would simply write

`import theme from 'themes/theme.js'`

To use aliases, you'll need to add them to your mix file `webpack.mix.js`.

``` js
mix.webpackConfig({
    resolve: {
        alias: {
            //adding react and react-dom may not be necessary for you but it did fix some issues in my setup.
            'react' : path.resolve('node_modules/react'),
            'react-dom' : path.resolve('node_modules/react-dom'),
            
            'components' : path.resolve('resources/js/src/components'),
            'pages' : path.resolve('resources/js/src/pages'),
            'themes' : path.resolve('resources/js/src/themes'),
            'layouts' : path.resolve('resources/js/src/layouts'),
            'hooks' : path.resolve('resources/js/src/hooks'),
        },
    },
});
```
<figcaption>webpack.mix.js</figcaption>
### Bundle and Extract React

After you've added your aliases, you'll need to tell webpack to bundle your files and extract libraries. In the same  `webpack.mix.js` file, add the following line. Notice that we're using `mix.react` and we are using `app.js`. If your app.js file already has legacy code, you could create a new app file for the React components.

``` js
mix.react('resources/js/app.js', 'public/js').extract(['react', 'react-dom']);
```
<figcaption>webpack.mix.js</figcaption>
## Rendering the components

This is where things get tricky.

Even though we aren't building an SPA, we still want to be able to build complex components that reuse multiple components. We're going to be mixing React components into blade files, and it would be great if we could retain some of the JS feel for the components so that we know we're referring to a React component, and it's not just a random div with an id.

Instead of referring to components as `<div id="MyComponent" />`

We are instead going to use `<MyComponent />`.

This isn't valid html, so if you want to use the id method, all you'll have to do is uncomment one of the lines in the ReactRenderer.js file coming up.

### Create a simple component

We need a simple component to test with, and this is about as simple as they get.

Create a new file with the following code in `src/components/MySimpleComponent.js`.

``` js
import React from 'react';

export default function MySimpleComponent(props) {

  return (
    <>
        <h2>This was loaded from a React component.</h2>
    </>
  );
}
```
<figcaption>components/MySimpleComponent.js</figcaption>
### Set up app.js

Next, we need to set up the app.js file. These are the lines that you'll need to add to the app.js file.

``` js
require('./bootstrap')
import React from 'react'
import ReactRenderer from './src/ReactRenderer'

import MySimpleComponent from 'components/MySimpleComponent'

const components = [
  {
    name: "MySimpleComponent",
    component: <MySimpleComponent />,
  },
]

new ReactRenderer(components).renderAll()

```
<figcaption>app.js</figcaption>

**A little explanation.**

In our app.js file we will import any components that we want to use within the blade files and add them to an array. We'll use the 'name' element to find all the references to the component in the blade files, and we'll use the 'component' element to render it.

Next we need to add the `ReactRenderer.js` file.

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

export default class ReactRenderer {

  constructor(components) {
    this.components = components;
  }

  renderAll() {

    for (let componentIndex = 0; componentIndex < this.components.length; componentIndex++) {

      // Use this to render React components in divs using the id. Ex, <div id="MySimpleComponent"></div>
      // let container = document.getElementById(this.components[componentIndex].name);

      // Use this to render React components using the name as the tag. Ex, <MySimpleComponent></MySimpleComponent>
      let containers = document.getElementsByTagName(this.components[componentIndex].name)

      if (containers && containers.length > 0) {

        for (let i = containers.length - 1; i >= 0; i--) {
          let props = this.getPropsFromAttributes(containers[i]);
          let element = this.components[componentIndex].component;

          if (props !== null) {
            element = React.cloneElement(
              element,
              props
            )
          }

          ReactDOM.render(element, containers[i]);
        }
      }
    }
  }

  // Turns the dom element's attributes into an object to use as props.
  getPropsFromAttributes(container) {
    let props = {};
    if (container.attributes.length > 0) {
      for (let attributeIndex = 0; attributeIndex < container.attributes.length; attributeIndex++) {
        let attribute = container.attributes[attributeIndex];
        if (this.hasJsonStructure(attribute.value)) {
          props[attribute.name] = JSON.parse(attribute.value);
        } else {
          props[attribute.name] = attribute.value;
        }
      }
      return props;
    }
    return null;
  }

  hasJsonStructure(str) {
    if (typeof str !== 'string')
      return false;
    try {
      const result = JSON.parse(str);
      const type = Object.prototype.toString.call(result);
      return type === '[object Object]' || type === '[object Array]';
    } catch (err) {
      return false;
    }
  }

}

```
<figcaption>ReactRenderer.js</figcaption>

You can read through the code to more fully understand what is happening. At its core, it's just finding all DOM elements that match your components and rendering them with any props included as well.

## Put it to work

Now that we have everything in place, we can start to build more components and add them to blade files.

Here are some examples of adding it to blade files.

``` php
...
<MySimpleComponent></MySimpleComponent>

@guest
<MySecondComponent
    title="This is using blade's {{'@'}}guest helper to show to 'Guests' only"
/>
@endguest

@auth
{{-- Remember to use "json_encode" to pass in objects --}}
<MySecondComponent
    title="This is showing to authed users"
    user="{{ json_encode(auth()->user()) }}"
/>
@endauth
...
```
<figcaption>app.blade.php</figcaption>

In the source code for this tutorial, I've also included a second component that accepts a `title` prop. This code is a snippet from the `app.blade.php` file in the source code.

If you download and run the sample project, you will get something that looks like this.

![Laravel + React](https://dev-to-uploads.s3.amazonaws.com/i/qfizp5tve23ow18oqjjp.png)

I encourage you to download the repo, explore, and make modifications to test it out. [https://github.com/jcz530/laravel-plus-react](https://github.com/jcz530/laravel-plus-react)