Como criar formulário de cadastro com Laravel 11 e React


Neste tutorial, será apresentado como criar um formulário de cadastro com Laravel 11 + Breeze + React. 

Primeiramente, será demonstrado como criar o formulário com React. 

Em seguida, será explicado como receber os dados do formulário com Laravel. 

Por fim, será mostrado como realizar o cadastro no banco de dados com Laravel.

Download do código fonte desenvolvido na aula: Download

PlayList sobre Laravel 11 + Breeze + React 11: Acessar

Receber as aulas gratuitas do curso de Laravel: Acessar


Para começar, é utilizado como base o projeto da aula "Como criar a página visualizar com Laravel 11 e React".

Criada a rota no arquivo "routes/web.php".

Route::get('/create-user', [UserController::class, 'create'])->name('users.create');

Criado o método "create" na controller "app/Http/Controllers/UserController.php". O método é responsável por carregar a "view Users/UserCreate.jsx".

public function create(): Response
{
    return Inertia::render('Users/UserCreate');
}

Criada a view com React no Laravel, em "resources/js/Pages/Users/UserCreate.js", com o formulário e a função handleSubmit, que recebe os dados do formulário.

import PrimaryButton from '@/Components/Button/PrimaryButton';
import SuccessButton from '@/Components/Button/SuccessButton';
import AuthenticatedLayout from '@/Layouts/AuthenticatedLayout';
import { Head, Link, useForm } from '@inertiajs/react';

export default function UserCreate({ auth, user }) {

    const {data, setData, post, processing, errors} = useForm({
        name: '',
        email: '',
        password: '',
        password_confirmation: '',
    });

    const handleSubmit = (e) => {

        e.preventDefault(); // Não atualizar a página

        // Enviar os dados para a rota cadastrar
        post(route('users.store'));
    }

    return (
        <AuthenticatedLayout
            user={auth.user}
            header={<h2 className="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">Usuário</h2>}
        >
            <Head title="Usuário" />

            <div className="py-4 max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div className="overflow-hidden bg-white shadow-lg sm:rounded-lg dark:bg-gray-800">
                    <div className="flex justify-between items-center m-4">
                        <h3 className="text-lg">Cadastrar</h3>
                        <div className="flex space-x-4">
                            <Link href={route('users.index')}>
                                <PrimaryButton className="text-sm">Listar</PrimaryButton>
                            </Link>
                        </div>
                    </div>

                    {/* Formulário para cadastar usuário */}
                    <div className="bg-gray-50 text-sm dark:bg-gray-700 p-4 rounded-lg shadow-md">

                        <form onSubmit={handleSubmit}>
                            <div className="mb-4">
                                <label htmlFor="name" className="block text-sm font-medium text-gray-700 ">Nome</label>
                                <input
                                    id="name"
                                    type="text"
                                    placeholder="Nome completo do usuário"
                                    value={data.name}
                                    onChange={(e) => setData('name', e.target.value)}
                                    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                                />
                                {errors.name && <span className="text-red-600">{errors.name}</span>}
                            </div>

                            <div className="mb-4">
                                <label htmlFor="email" className="block text-sm font-medium text-gray-700 ">E-mail</label>
                                <input
                                    id="email"
                                    type="email"
                                    placeholder="Melhor e-mail do usuário"
                                    value={data.email}
                                    onChange={(e) => setData('email', e.target.value)}
                                    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                                />
                                {errors.email && <span className="text-red-600">{errors.email}</span>}
                            </div>

                            <div className="mb-4">
                                <label htmlFor="password" className="block text-sm font-medium text-gray-700 ">Senha</label>
                                <input
                                    id="password"
                                    type="password"
                                    autoComplete="password"
                                    value={data.password}
                                    onChange={(e) => setData('password', e.target.value)}
                                    placeholder="Senha para o usuário acessar o sistema"
                                    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                                />
                                {errors.password && <span className="text-red-600">{errors.password}</span>}
                            </div>

                            <div className="mb-4">
                                <label htmlFor="password_confirmation" className="block text-sm font-medium text-gray-700 ">Confirmar a Senha</label>
                                <input
                                    id="password_confirmation"
                                    type="password"
                                    autoComplete="password_confirmation"
                                    placeholder="Confirmar a senha"
                                    value={data.password_confirmation}
                                    onChange={(e) => setData('password_confirmation', e.target.value)}
                                    className="mt-1 block w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
                                />
                                {errors.password_confirmation && <span className="text-red-600">{errors.password_confirmation}</span>}
                            </div>

                            <div className="flex justify-end">
                                <SuccessButton
                                    type="submit"
                                    disabled={processing}
                                    className="text-sm"
                                >
                                    Cadastrar
                                </SuccessButton>
                            </div>

                        </form>
                    </div>
                </div>
            </div>
        </AuthenticatedLayout>
    );
}

Os dados do formulário acima são enviados para a rota "users.store", sendo necessário criá-la no arquivo "routes/web.php".

Route::post('/store-user', [UserController::class, 'store'])->name('users.store');

Criado o método "store" na controller "app/Http/Controllers/UserController.php". O método é responsável por cadastrar o usuário no banco de dados e redirecionar para a tela de visualização "users.show".

public function store(Request $request)
{

    // Validar os dados de formulário
    $request->validate(
        [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:8|max:255|confirmed',
        ],
        [
            'name.required' => 'O campo nome é obrigatório.',
            'name.string' => 'O nome deve ser uma string válida.',
            'name.max' => 'O nome não pode ter mais que 255 caracteres.',
            'email.required' => 'O campo e-mail é obrigatório.',
            'email.string' => 'O e-mail deve ser uma string válida.',
            'email.email' => 'O e-mail deve ser um endereço de e-mail válido.',
            'email.max' => 'O e-mail não pode ter mais que 255 caracteres.',
            'email.unique' => 'Este e-mail já está cadastrado.',
            'password.required' => 'O campo senha é obrigatório.',
            'password.string' => 'A senha deve ser uma string válida.',
            'password.min' => 'A senha deve ter no mínimo 8 caracteres.',
            'password.confirmed' => 'A confirmação da senha não corresponde.',
        ]
    );

    $user = User::create([
        'name' => $request->name,
        'email' => $request->email,
        'password' => $request->password,
    ]);

    return Redirect::route('users.show', ['user' => $user->id])->with('success', 'Usuário cadastrado com sucesso!');
}

Para receber a mensagem de sucesso salva na sessão success, é necessário acrescentar o flash no middleware "app/Http/Middleware/HandleInertiaRequests.php".

return [
    ...parent::share($request),
    'auth' => [
        'user' => $request->user(),
    ],
    'flash' => [
        'success' => fn () => $request->session()->get('success')
    ],
];

Na página de visualização, ou seja, na view "resources/js/Pages/Users/UserShow.js", é necessário receber a mensagem que está em props.

import { Head, Link, usePage } from '@inertiajs/react';

const {flash} = usePage().props;

Para finalizar, a mensagem de sucesso é impressa.

{flash.success && (<div className="p-3 m-3 text-sm text-green-800 rounded-lg bg-green-50 dark:bg-gray-800 dark:text-green-400">{flash.success}</div>)}

Baixar o código-fonte completo do projeto.

Bom, era isso. Espero que o tutorial tenha sido útil!