Wednesday, 21st November 2018
21 November 2018
App demo

Using React in a Laravel application

Vue.js is with no doubts the preferred JavaScript framework in the Laravel community. In fact, a fresh Laravel application comes with Vue.js already set up out of the box. Prefer to use React instead? Then you are in the right place, as we’ll be looking at how to use React in a Laravel application in this tutorial.

Prerequisites

This tutorial assumes the following:

  • Basic knowledge of PHP and Laravel
  • Basic knowledge of JavaScript and React
  • PHP installed on your computer
  • Composer installed on your computer
  • Laravel installer installed on your computer
  • SQLite installed on your computer

What we’ll be building

For the purpose of demonstrating how to use React in a Laravel application, we’ll build a task management app. Below is a working demo of the final application:

Planning the application

Our task management app, will consist of two main components: tasks and projects. Let’s break each of these component down.

  • Tasks: a task is an item that needs to be done by a user and usually consists of a brief and concise title of what needs to be done to complete that task. Tasks also need to indicate whether they have been completed or not. Finally, a task is usually associated with a project that contains similar or related tasks.
  • Projects: projects group related tasks together and usually have a descriptive name, and a description associated with them. We also need to be able to indicate whether or not a project is completed.

With that said, our app will have the following tables and fields:

Table Fields
tasks id, title, project_id, is_completed, created_at, updated_at
projects id, name, description, is_completed, created_at, updated_at

Let’s get started already!

Getting started

We’ll start by creating a fresh Laravel application:

Once that’s is done, we need to swap the default Vue.js scaffolding with React. Luckily for us, there is a presetArtisan command we can use for that. The preset command was added in Laravel 5.5, which allows us to specify our JavaScript framework of choice. To specify we want to use React in place of Vue.js, we’ll run the command below:

We should now have an Example.js file inside resources/assets/js/components, which is a basic React component. Also, resources/assets/js/app.js has been updated to make use of the Example component.

Next, run the command below to install our app dependencies:

Creating the app models and migrations

As already outlined in the planning the application section, we need to create two models: Task and Project:

Adding the -m flag to the make:model command will generate the accompanying migration for the model.

Next, open app/Task.php and update it content as below:

We specify the fields we want to be mass assignable.

Similarly, open app/Project.php and update as below:

In addition to specifying the fields we want mass assignable, we also define a relationship between the Project and the Task models using the tasks method. This is a one-to-many relationship, as a project can have numerous number of tasks, but a task can only belong to a particular project.

You’ll notice we didn’t define the inverse of the relationship on the Task model, as we are only defining what’s needed for the purpose of this tutorial.

Next, let’s update the generated migrations for our models. Open database/migrations/TIMESTAMP_create_tasks_table.php and update the up method as below:

You’ll notice we are setting the is_completed field to be false by default.

Similarly, open database/migrations/TIMESTAMP_create_projects_table.php and update the up method as below:

Before we run the migrations, let’s set up our database. We’ll be using SQLite. So, create a database.sqlite file inside the database directory then update the .env file as below:

Run the migrations:

Creating the app API

We’ll start by defining the API endpoints. Open routes/api.php and replace it content with the code below:

Here, we define endpoints for fetching all projects as well for fetching a single project. Then endpoints for creating new projects and tasks respectively. Finally, endpoints for marking a project and task as completed respectively.

Next, let’s move on to create the controllers:

Open app/Http/Controllers/ProjectController.php and update it as below:

The index method fetches all the projects that are yet to be marked as completed in a descending order to when they are created. Also, we get the number of tasks that are yet to be marked as completed belonging to individual project. Then we convert the projects to JSON and return them.

The store method is used to create a new project. First, it validates the incoming request data against the defined rules for each field. Then once the validation passes, we create a new project using the validated data in the database, and return a JSON response.

The show method fetches a single project by its id. In addition to fetching the project, we also fetch all the tasks that are yet to be marked as completed for the particular project. Finally, we return the project in JSON.

The markAsCompleted method simply update a specified project by setting is_completed to true.

Next, let’s open app/Http/Controllers/TaskController.php and update it as below:

We won’t be going over each of the method as they are similar to those in the ProjectController.

With that, we have completed the API for our application.

Now, let’s move to the frontend of our application.

Creating a wildcard route

We’ll be using React Router to handle routing in our application. For this, we need to render a single view file for all our application routes. Open routes/web.php and replace it content with the code below:

We define a wildcard route. An app.blade.php view file will be rendered for all our app routes. This way, we can render our React components from within this view file, and we’ll be able use all the goodies that React has to offer.

Next, let’s create the app.blade.php view file. We’ll create this file directly within the resources/views directory, then paste the following code in it:

We add references to both a CSS file and a JavaScript file (containing React and other dependencies bundled up). We have an empty div with an id of app. This is where our React components will be rendered. Also, you’ll notice we have a meta tag containing a CSRF token, which will be attached as a common header to all outgoing HTTP requests we make using Axios. This is defined in resources/assets/js/bootstrap.js.

Creating the App componnet

The App component will serve as the base for our React components. Let’s rename the default Example component to App and replace it content with the following code:

We render a Header component (which we’ll create shortly). The Header component will be rendered for all our app pages. As you can see, we are making use of React Router, so let’s install it:

While that’s installing, open and update resources/assets/js/app.js as below:

Instead of referencing the Example component, we reference the App component we just created.

Creating the Header component

Let’s create the Header component referenced above. Create a new Header.js file within the resources/assets/js/components directory and paste the code below in it:

A basic Bootstrap navbar with a link to the homepage. As you can see, we are making use of the Link component from React Router. This will prevent our page from refreshing whenever we navigate around our app.

Displaying all projects yet to be completed

To display a list of projects that are yet to be completed, we’ll create a ProjectsList component. Within resources/assets/js/components, create a new ProjectsList.js file and paste the code below in it:

We define a projects state and initialize it to be an empty array. Using React’s componentDidMount lifecycle, we make an HTTP request using Axios to our app API endpoint to fetch all the projects that are yet to be marked as completed. Then we update the projects state with the response data gotten from our app API.

Finally, we display a list of the projects by iterating over the projects state.

Before we go on to test this out, let’s update the App component as below:

Here, we add a new route / (homepage). So whenever the / route is visited, the ProjectsList component will be rendered.

Creating a new project

From the ProjectsList component, you’ll notice we have a link to create a new project. Let’s implement it. Create a new NewProject.js file within resources/assets/js/components, and paste the code below in it:

This component renders a form for creating a new project. We define some states: namedescription and errors. Then we define a handleFieldChange method that gets called whenever the create a new project form input fields changes. Base on these changes, we update the states (name and description) accordingly. For this to work, we add an onChange event to each of the field.

Once the form is submitted, a handleCreateNewProject method is called, which first prevents the default behavior of form submission. Then it makes an HTTP request to our app API endpoint passing along the form data. If everything went well, we simply redirect the user to the homepage. otherwise, we update the errors state with the response error gotten from our app API.

The hasErrorFor method checks if the specified field has an error or not, and will either return true or false. The renderErrorFor method renders the error message for the specified field, if the field has error.

Just as we did with the ProjectsList component, let’s add the NewProject component to the App component. Update the App component as below:

We define the route /create for creating a new project, and the NewProject component will be rendered whenever the route is visited.

Display a single project

Now let’s display a single project. You’ll notice from the ProjectsList component that each project is listed with an anchor (to the project ID) to view the project. Create a new SingleProject component within resources/assets/js/components and paste the code below in it:

We define two state properties: project and tasks. The project state will hold the details of the specified project, while the tasks state will hold the tasks for the project. Inside the componentDidMount lifecycle method, we make an HTTP request to our app API to fetch the project with the specified project ID. The project ID is passed to the URL, so we can get it using this.props.match.params.id. Then we update the state (project and tasks) with the response data gotten from our app API.

Finally, we display the details about the project as well as the project’s tasks. Also, we display buttons to mark the project and its tasks as completed.

Next, let’s add the SingleProject component to the App component. Update the App component as below: