CRUD con Laravel 9 y React

En este tutorial te mostraré cómo crear un CRUD básico con Laravel 9 en el backend y React en el frontend. Sin más manos a la obra.

Requisitos previos

  1.  Ambiente de desarrollo como XAMPP, WAMP o Laragon.
  2.  Composer instalado de manera global.
  3.  Node instalado en el sistema operativo.
  4.  Tener instalado PHP 8 (Laravel 9 solo corre con esta versión de PHP)

Configurar backend en Laravel 9

1. Crear proyecto en Laravel 9

Ve a la raíz de tu ambiente de desarrollo y crea una carpeta llamada crud-laravel-9-react y dentro de ella desde la terminal de comandos escribe:

composer create-project laravel/laravel api

Desde la terminal de comandos ingresa a la recién creada carpeta api.

2. Crear base de datos

Para crear una nueva base de datos para tu CRUD en Laravel 9 y React es necesario acceder a la consola de MySQL para ello desde la terminal de comandos escribe:

mysql -u root -p

Accede con tus credenciales y luego escribe:

CREATE DATABASE crud_laravel_9_react CHARACTER SET utf8 COLLATE utf8_spanish_ci;

para salir de la consola de MySQL solo escribe exit.

Con tu editor de textos abre el archivo .env y agrega el nombre de la base de datos que usarás para este proyecto:

Agregar nombre de db a archivo .env

3. Crear Modelo Empleado

Para este tutorial crearás un CRUD que maneje los datos de empleados, para crear el Modelo en la terminal escribe:

php artisan make:model Employee -m

4. Crear controlador

Para crear el controlador escribe en la terminal de comandos:

php artisan make:controller Api/EmployeeController --api

5. Configurar archivo de migración

Abre el archivo api/database/migrations/…create_employees_table.php y agrega los campos ‘name’, ‘last_name’, ‘job’, ‘phone’, ‘address’, ‘age’ a la tabla employees:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('employees', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('last_name');
            $table->string('job');
            $table->string('phone');
            $table->text('address');
            $table->string('age');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('employees');
    }
};

6. Configurar Modelo Employee

Para habilitar la asignación masiva a la tabla employees abre el archivo api/app/Models/Employee.php y crea la propiedad fillable como se muestra:

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Employee extends Model
{
    use HasFactory;

    protected $fillable = ['name', 'last_name', 'job', 'phone', 'address', 'age'];
}

Corre las migraciones desde la terminal escribiendo:

php artisan migrate

7. Configurar controlador

Abre el archivo api/app/Http/Controllers/Api/EmployeeController  y en cada método agrega el código correspondiente:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\Employee;

class EmployeeController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $employees = Employee::all();
        return $employees;
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request)
    {
        $employee = new Employee();
        $employee->name = $request->name;
        $employee->last_name = $request->last_name;
        $employee->job = $request->job;
        $employee->phone = $request->phone;
        $employee->address = $request->address;
        $employee->age = $request->age;

        $employee->save();
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($id)
    {
        $employee = Employee::find($id);
        return $employee;
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        $employee = Employee::findOrFail($request->id);
        $employee->name = $request->name;
        $employee->last_name = $request->last_name;
        $employee->job = $request->job;
        $employee->phone = $request->phone;
        $employee->address = $request->address;
        $employee->age = $request->age;

        $employee->save();
        return $employee;
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($id)
    {
        $employee = Employee::destroy($id);
        return $employee;
    }
}

8. Crear las rutas en Laravel 9

Como Laravel solo lo usarás para el backend, las rutas se deben de crear en el archivo api para ello abre el archivo api/routes/api.php y agrega las siguientes rutas:

<?php

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Api\EmployeeController;

/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/

Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
    return $request->user();
});

Route::controller(EmployeeController::class)->group(function (){
    Route::get('/employees', 'index');
    Route::post('/employee', 'store');
    Route::get('/employee/{id}', 'show');
    Route::put('/employee/{id}', 'update');
    Route::delete('/employee/{id}', 'destroy');

});

Hasta aquí esta preparado el backend de la aplicación, ahora vas a configurar el frontend.

Configurar frontend en React

1. Crear proyecto React

Para crear la carpeta del proyecto para el frontend en tu terminal de comando sube un nivel para quedar al mismo nivel de la carpeta api y escribe la instrucción:

npx create-react-app frontend

Sí te pregunta: Need to install the following packages escribe ‘y’ y luego presiona la tecla Enter para continuar con la instalación. Se creará la carpeta frontend al lado de la carpeta api:

CRUD con Laravel 9 y React

2. Instalar dependencias

Desde la terminal de comandos ingresa a la carpeta recién creada frontend y para instalar las dependencias que necesitas para este proyecto escribe:

npm i axios bootstrap react-router-dom@6

3. Configurar archivos

Para agregar bootstrap abre el archivo frontend/src/index.js y agrega la siguiente línea de código:

import 'bootstrap/dist/css/bootstrap.min.css';

CRUD con Laravel 9 y React

Hay componentes que se crean por default pero que para este proyecto no se usarán, en el repositorio GitHub del proyecto encontrarás actualizado los archivos que he quitado.

4. Crear componentes para React

Crea la carpeta frontend/src/components y dentro de ella crea los archivos ‘CreateEmployee.js’, ‘EditEmployee.js’ y ‘ShowEmployees.js’, que son los componentes que usarás para este proyecto:

Crea los nuevo componentes

5. Configurar componente ShowEmployee

Abre el archivo frontend/src/components/ShowEmployees.js y copia el siguiente código:

import React, {useEffect, useState} from 'react'
import axios from 'axios'
import {Link} from 'react-router-dom'

const endpoint = 'http://localhost:8000/api'
const ShowEmployees = () => {

    const [employees, setEmployees] = useState([])
    useEffect ( ()=> {
        getAllEmployees()
    }, [])

    const getAllEmployees = async () => {
        const response = await axios.get(`${endpoint}/employees`)
        setEmployees(response.data)
    }

    const deleteEmployee = async (id) => {

       await axios.delete(`${endpoint}/employee/${id}`)
       getAllEmployees()
         
    }
  return (
    <div>
        <div className='d-grid gap-2'>
            <Link to="/create" className='btn btn-success btn-lg mt-2 mb-2 text-white'>Create</Link>
        </div>
        <table className='table table-striped'>
            <thead className='bg-primary text-white'>
                <tr>
                    <th>Name</th>
                    <th>Last Name</th>
                    <th>Job</th>
                    <th>Phone</th>
                    <th>Address</th>
                    <th>Age</th>
                    <th>Action</th>
                </tr>
            </thead>
            <tbody>
                { employees.map( (employee) => (
                    <tr key={employee.id}>
                        <td>{employee.name}</td>
                        <td>{employee.last_name}</td>
                        <td>{employee.job}</td>
                        <td>{employee.phone}</td>
                        <td>{employee.address}</td>
                        <td>{employee.age}</td>
                        <td>
                            <Link to={`/edit/${employee.id}`} className='btn btn-info'>Edit</Link>
                            <button onClick={ ()=>deleteEmployee(employee.id)} className='btn btn-danger'>Delete</button>
                        </td>
                    </tr>
                ))}                
            </tbody>
        </table>
    </div>
  )
}

export default ShowEmployees

6. Configurar componente CreateEmployee

Desde tu editor de código abre el archivo frontend/src/components/CreateEmployee.js y agrega el siguiente código:

import axios from 'axios'
import React, {useState} from 'react'
import { useNavigate } from 'react-router-dom'

const endpoint = 'http://localhost:8000/api/employee'
const CreateEmployee = () => {

    const [name, setName] = useState('')
    const [last_name, setLastName] = useState('')
    const [job, setJob] = useState('')
    const [phone, setPhone] = useState('')
    const [address, setAddress] = useState('')
    const [age, setAge] = useState('')
    const navigate = useNavigate()

    const store = async (e) => {
        e.preventDefault();
        await axios.post(endpoint, {name: name, last_name: last_name, job: job, phone: phone, address: address, age: age})
        navigate('/')

    }
  return (
    <div>
        <h2>Creat a new employee</h2>
        <form onSubmit={store}>
            <div className='mb-3'>
                <label className='form-label'>Name</label>
                <input 
                    value={name} 
                    onChange={ (e)=> setName(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Last Name</label>
                <input 
                    value={last_name} 
                    onChange={ (e)=> setLastName(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Job</label>
                <input 
                    value={job} 
                    onChange={ (e)=> setJob(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Phone</label>
                <input 
                    value={phone} 
                    onChange={ (e)=> setPhone(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Address</label>
                <input 
                    value={address} 
                    onChange={ (e)=> setAddress(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Age</label>
                <input 
                    value={age} 
                    onChange={ (e)=> setAge(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <button type='submit' className='btn btn-success'>Save</button>
        </form>
    </div>
  )
}

export default CreateEmployee

7. Configurar componente EditEmployee

Abre el archivo frontend/src/components/EditEmployee.js y agrega el siguiente código:

import axios from 'axios'
import React,{useState, useEffect} from 'react'
import { useNavigate, useParams } from 'react-router-dom'

const endpoint = 'http://localhost:8000/api/employee/'

const EditEmployee = () => {

    const [name, setName] = useState('')
    const [last_name, setLastName] = useState('')
    const [job, setJob] = useState('')
    const [phone, setPhone] = useState('')
    const [address, setAddress] = useState('')
    const [age, setAge] = useState('')
    const navigate = useNavigate()
    const {id} = useParams()

    const update = async (e) => {
        e.preventDefault();
        await axios.put(`${endpoint}${id}`, {
            name: name,
            last_name: last_name,
            job: job,
            phone: phone,
            address: address,
            age: age
        })
        navigate('/')
    }

    useEffect( () =>{

        const getEmployeeById = async () => {
            const response = await axios.get(`${endpoint}${id}`)
            setName(response.data.name)
            setLastName(response.data.last_name)
            setJob(response.data.job)
            setPhone(response.data.phone)
            setAddress(response.data.address)
            setAge(response.data.age)
        }
        getEmployeeById()
        
    }, [])
  return (
    <div>
        <h2>Edit employee</h2>
        <form onSubmit={update}>
            <div className='mb-3'>
                <label className='form-label'>Name</label>
                <input 
                    value={name} 
                    onChange={ (e)=> setName(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Last Name</label>
                <input 
                    value={last_name} 
                    onChange={ (e)=> setLastName(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Job</label>
                <input 
                    value={job} 
                    onChange={ (e)=> setJob(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Phone</label>
                <input 
                    value={phone} 
                    onChange={ (e)=> setPhone(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Address</label>
                <input 
                    value={address} 
                    onChange={ (e)=> setAddress(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <div className='mb-3'>
                <label className='form-label'>Age</label>
                <input 
                    value={age} 
                    onChange={ (e)=> setAge(e.target.value)}
                    type='text'
                    className='form-control'
                />
            </div>

            <button type='submit' className='btn btn-success'>Update</button>
        </form>
    </div>
  )
}

export default EditEmployee

8. Configurar archivo App.js

Ahora con tu editor de textos abre el archivo frontend/src/App.js y agrega el siguiente código:

import './App.css';

import { BrowserRouter, Routes, Route } from 'react-router-dom';
//se importa el componente
import ShowEmployees from './components/ShowEmployees';
import CreateEmployee from './components/CreateEmployee';
import EditEmployee from './components/EditEmployee';

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Routes>
          <Route path='/' element={ <ShowEmployees/>} />
          <Route path='/create' element={ <CreateEmployee/>} />
          <Route path='/edit/:id' element={ <EditEmployee/>} />
        </Routes>
      </BrowserRouter>
    </div>
  );
}

export default App;

9. Probar proyecto

Ya tienes todo lo necesario para que tu proyecto funcione, para probarlo primero es necesario inicializar tanto el backend en Laravel como el frontend en React, abre dos terminales e ingresa a cada carpeta desde cada una de ellas, en la terminal de la carpeta api escribe:

php artisan serve

Y en la terminal de la carpeta frontend escribe:

npm start

El navegador se abrirá y te mostrará algo así:

CRUD con Laravel 9 y React

Prueba creando un nuevo registro:

Crea un nuevo registro en el sistema

Puedes ver que el registro se creo correctamente:

El registro se creo correctamente

Conclusión

En este tutorial te mostré cómo crear un CRUD básico con Laravel 9 como backend y React en el frontend. Si te sirvió te invito a compartirlo en tus redes sociales y si tienes dudas o comentarios déjalos en la caja de comentarios estaré al pendiente de ellos. Saludos.

Repositorio GitHub

Te puede interesar: Cómo clonar un proyecto en Laravel

6 COMENTARIOS

  1. Men te juro que estaba loco porque en la empresa me estan embutiendo laravel y yo pues llevo rato con react
    claro con api rest puedo hacer la api en laravel y seguir aprendiendo de mi framework favorito React js

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.