Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jollysoundcake1's avatar

Laravel Breeze React Inertia - render data in a custom component imported to Dashboard

Hi Everyone,

I have installed the Breeze + React starter pack following the docs.

In my Dashboard.jsx I imported a custom component I made, rendered fine.

Problem is, now I am trying to make that custom component display data retrieved from a controller, but so far I'm running into problems.

Currently I have:

app/Http/Controllers/UserDetailsController.php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Inertia\Inertia;
use App\Models\User;

class UserDetailsController extends Controller
{
    /**
     * Return all users.
     *
     * @return \Inertia\Response
     */
    public function __invoke()
    {
        return Inertia::render('UserDetails', [
            'users' => User::all(),
        ]);
    }
}

resources/js/Pages/Dashboard.jsx

import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import { Head } from '@inertiajs/inertia-react';
import UserDetails from '@/Components/UserDetails';

export default function Dashboard(props) {
    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Dashboard</h2>}
        >
            <Head title="Dashboard" />

            <div className="py-12">
                <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
                    <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                        <div className="p-6 bg-white border-b border-gray-200">You're logged in!</div>
                        <div className="p-6 bg-white border-b border-gray-200" id="user-details"></div>
                    </div>
                </div>
            </div>
        </Authenticated>
    );
}

resources/js/Components/UserDetails.jsx

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

export default function UserDetails({userdetails}) {
    return (
        <div className="container">
            <div className="row justify-content-center">
                <div className="col-md-8">
                    <div className="card">
                        <div className="card-header">Users header</div>
                        <ul>
                            {Object.keys(userdetails).map(function (key, index) {
                                return <li key={index}>{userdetails[key]}</li>;
                            })}
                        </ul>
                        <div className="card-body">Card body</div>
                    </div>
                </div>
            </div>
        </div>
    );
}

if (document.getElementById('user-details')) {
    ReactDOM.render(<UserDetails/>, document.getElementById('user-details'));
}

The Dashboard page is not rendering with that setup (the component renders on the dashboard fine with just plain markup). Dev tools is throwing an error: "UserDetails.jsx:12 Uncaught TypeError: Cannot convert undefined or null to object"

What am I missing? Need to set up a route certain way?

Thanks for help in advance

0 likes
26 replies
Sinnbeck's avatar

I am unsure why you are doing this if you are using inertia. Inertia is for spa

if (document.getElementById('user-details')) {
    ReactDOM.render(<UserDetails/>, document.getElementById('user-details'));
}
1 like
Sinnbeck's avatar

You add it to the markup instead

<div className="p-6 bg-white border-b border-gray-200" id="user-details">
    <UserDetails userdetails={props.users} />
</div>

This assumes that you pass users down in the dashboard controller

jollysoundcake1's avatar

@Sinnbeck Thanks, after modifying Dashboard.jsx to use this bit of markup instead, the "Uncaught TypeError: Cannot convert undefined or null to object" error persists - the difference is that in the browser nothing loads anymore ("plain white" page), previously just the UserDetails.jsx component failed to render

Sinnbeck's avatar

@jollysoundcake1 most likely due to this. I assume userdetails is an array of users or?

{Object.keys(userdetails).map(function (key, index) {
                                return <li key={index}>{userdetails[key]}</li>;
                            })}
Sinnbeck's avatar

Oh and a small tip. Never use index as key. If you reorder your data, react gets really confused and screws up its references

1 like
jollysoundcake1's avatar

@Sinnbeck that is indeed the culprit, userdetails is undefined in UserDetails.jsx - it's meant to be all users retrieved by 'userdetails' => User::all() in the controller (it's not 'users'=> as I posted here, it's 'userdetails')

Sinnbeck's avatar

@jollysoundcake1 you need to put it in the dashboard controller as that's where all data comes from for this specific page. One controller per page, not per component :)

jollysoundcake1's avatar

@Sinnbeck

the dashboard route appears to be rendering a component anyway?

Route::get('/dashboard', function () {
    return Inertia::render('Dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Sinnbeck's avatar

@jollysoundcake1 shared data. But it is then available on all pages.

Or regular ajax requests where you don't use inertia. But inertia works in the same way as a controller -> blade view works (with the exception of blade now having components with its own data)

Sinnbeck's avatar

@jollysoundcake1 it is rendering a page component. Check your app.jsx file and you will see it is passing Dashboard to Pages/

Inertia::render('Dashboard', [
    'users' => User::all(), //all users. So an array 
    'userdetails' => auth()->user() //current user. So an object 
] );
1 like
jollysoundcake1's avatar

@Sinnbeck Thanks,

If I modify the dashboard route to this then all works fine:

Route::get('/dashboard', function () {
    return Inertia::render('Dashboard',
        ['userdetails' => User::all(),]
    );
})->middleware(['auth', 'verified'])->name('dashboard');

but I don't like this solution as I want to do some more logic before returning user data, and I don't want the route code to look messy

that's why I'm looking to abstract that elsewhere

jollysoundcake1's avatar

@Sinnbeck thanks will do,

And thanks for all your input, definitely good food for thought - feel free to chip in with anything else if you can think of something;)

Sinnbeck's avatar

@jollysoundcake1 let me just show you how to display your list of users. I just named the variable users as that makes more sense if it's an array (multiple users)

{users.map(function (user) {
                                return <li key={user.id}>{user.name}</li>;
                            })}
1 like
Sinnbeck's avatar

That's ok. My formatting is terrible as well

1 like
jollysoundcake1's avatar

@Sinnbeck

Right, made some progress with a few other things, but this prop passing still haunts me. Maybe it's the heat lol

Opted in for a very simple, custom middleware to redirect a user based on role (Spatie), made a custom jsx dashboard for a user with a certain role, and its controller. Routing works, redirects work, everything works, except once again, the var I'm passing is 'undefined' causing a rendering error.

app/Http/Middleware/CheckUserRole.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class CheckUserRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse)  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next, ...$guards)
    {
        $user = Auth::user();
        if ($user->hasRole('BankAdmin')) {
            return redirect('/admin/dashboard');
        }
        if ($user->hasRole('BankUser')) {
            return redirect('/user/dashboard');
        }
        return redirect('/');
    }
}

in my routes/web.php

Route::get('/', function () {
    return Inertia::render('Welcome', [
        'canLogin' => Route::has('login'),
        'canRegister' => Route::has('register'),
        'laravelVersion' => Application::VERSION,
        'phpVersion' => PHP_VERSION,
    ]);
});

Route::get('/dashboard', function () {
    return Inertia::render('Dashboard',
    );
})->middleware(['auth', 'verified', 'checkrole'])->name('dashboard');

Route::get('/user/dashboard', UserDashboardController::class);

require __DIR__ . '/auth.php'; 

app/Http/Controllers/UserDashboardController.php

<?php

namespace App\Http\Controllers;

use Inertia\Inertia;
use Illuminate\Http\Request;

class UserDashboardController extends Controller
{
    /**
     * Return all users.
     *
     * @return \Inertia\Response
     */
    public function __invoke()
    {
        return Inertia::render('UserDashboard', [
            'message' => 'You are logged in as BankUser',
        ]);
    }
}

resources/js/Pages/UserDashboard.jsx

import React from 'react';
import Authenticated from '@/Layouts/Authenticated';
import {Head} from '@inertiajs/inertia-react';

export default function UserDashboard(props) {
    return (
        <Authenticated
            auth={props.auth}
            errors={props.errors}
            message={props.message}
            header={<h2 className="font-semibold text-xl text-gray-800 leading-tight">Dashboard</h2>}
        >
            <Head title="User Dashboard"/>

            <div className="py-12">
                <div className="max-w-7xl mx-auto sm:px-6 lg:px-8">
                    <div className="bg-white overflow-hidden shadow-sm sm:rounded-lg">
                        <div className="p-6 bg-white border-b border-gray-200">You're logged in - BankUser!{message} </div>
                    </div>
                </div>
            </div>
        </Authenticated>
    );
}

Any idea why {message} is undefined?

Sinnbeck's avatar

@jollysoundcake1 it's often a good idea to use console.log for debugging :)

UserDashboard(props) {
    console.log(props) 
    return (
1 like
jollysoundcake1's avatar

@Sinnbeck For sure, I actually see my message when I console.log the props (along with auth etc). Just don't get why I can't access it on the page (undefined)

jollysoundcake1's avatar

Update:

I can access {props.message} directly no problem, just not when I specify message={props.message} and then try to use {message} on the page

So I guess it works;) Although I am missing something to be able to use {message}

Sinnbeck's avatar
Sinnbeck
Best Answer
Level 102

If you want to leave out the word props, you can extract your props

export default function UserDashboard({auth, errors, message}) {

Please or to participate in this conversation.