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

oliverbusk's avatar

Inertia.js small app functionality - best practice

Hi there.

I am trying to wrap my head around Inertia.js together with Laravel. For the past time, I've been using Livewire quite heavily.

In Livewire, I am quite used to be able to thinking in "Components" - that is, small parts of Livewire components that I can place in my pages, which functionality such as:

  • Follow a friend
  • Mark post as spam
  • Like a post
  • Approve a request

For all of these things, I can quickly add the desired functionality in a Livewire component:

public function follow($user){
	return $this->user->follow($user);
}

public function like($post){
	return $post->likes->create([...]);
}

etc...

I can't quite wrap my head around how to do this in Inertia.js and what's the conventions for this are. My doubts are, I need to think more in "full pages". So where to put these small niceties that you often find in apps?

0 likes
3 replies
drehimself's avatar

It's not much different from how you would structure a normal Vue app. I personally don't extract to a component until either:

  • I need that same functionality somewhere else and don't want to repeat myself
  • The code for a "full page" component gets quite long and extracting to smaller components makes it neater.

Take a look at the source for the demo Ping CRM app: https://github.com/inertiajs/pingcrm

Most of the CRUD functionality is built right into the full page components in the "Pages" folder. For anything that is needed in multiple places, it's extracted to smaller re-usable components in the "Shared" folder.

oliverbusk's avatar

@drehimself Thanks for your answer, @drehimself! It's not the CRUD actions I am struggling with. It's more the functionality that I would normally use a Livewire component with, I am having a hard time figuring out how to structure.

We can take an example. I am building a page where moderators can look through posts and either approve, skip or deny them. In Livewire, that would normally look like this:

<textarea wire:model="content" />
<div class="flex justify-between">
   <button wire:click="approvePost">Approve post</button>
   <button wire:click="denyPost">Deny post</button>
   <button wire:click="skipPost">Skip post</button>
</div>

And in the component:

class Moderator extends Component {

    protected $posts;
    public $currentPost;
    public string $content = '';

    public function mount()
    {
        $this->posts = Post::where([...])->get();
        $this->currentPost = $this->posts->first();
        $this->content = $this->currentPost->content;
    }
	
	public function approvePost(){

		//1. Update the database.	
    	$this->currentPost->update(['status' => 'approved']);

       //2. Get the next post.
      // $this->currentPost .......

       //3. Set the content in the frontend to the next post.
       //$this->content = ...

      //4. Show a success banner
      //$this->notify('success', 'Post approved'); 
     
    }

   public function denyPost(){

		//1. Update the database.	
    	$this->currentPost->update(['status' => 'denied']);

       //2. Get the next post.
      // $this->currentPost .......

       //3. Set the content in the frontend to the next post.
       //$this->content = ...

      //4. Show a success banner
      //$this->notify('success', 'Post denied'); 
     
    }

   public function skipPost(){

		//1. Update the database.	
    	$this->currentPost->update(['status' => 'skipped']);

       //2. Get the next post.
      // $this->currentPost .......

       //3. Set the content in the frontend to the next post.
       //$this->content = ...

      //4. Show a success banner
      //$this->notify('success', 'Post skipped'); 
     
    }
}

So the above code example (pseudo-code, so bear with me) illustrates how this can be solved very fast in Livewire - without setting up any additional URL endpoints. Now, with Inertia.js - how would I achieve this?

I figure that in my page, I must create JS methods to send the request - something like:

<!-- Index.vue -->
import { useForm } from '@inertiajs/inertia-vue3';
const form = useForm({.......});

const approvePost = () => {
    form.put(route('posts.moderator.update'), {
		errorBag: 'approvePost',
        preserveScroll: true,
    }
}
const denyPost = () => {
    form.put(route('posts.moderator.update'), {
		errorBag: 'approvePost',
        preserveScroll: true,
    }
}
const skipPost = () => {
    form.put(route('posts.moderator.update'), {
		errorBag: 'approvePost',
        preserveScroll: true,
    }
}

And then the logic is pushed to the backend? (Controller)

I guess what confuses me is that I will need to create endpoints/controllers for each and every action my site performs (when it needs to hit the database at least...)?

drehimself's avatar

@oliverbusk

I guess what confuses me is that I will need to create endpoints/controllers for each and every action my site performs (when it needs to hit the database at least...)?

Yes, that's correct. If you want to think of it in terms of Livewire, the .blade.php file is the "Frontend" or the "Vue" part and the corresponding .php livewire component is just standard Laravel Controllers when using Inertia.

Please or to participate in this conversation.