Hi there. While adding Livewire to a project, we missed a way to have dependencies injected at render time.
I was wondering if it would be ok to make it possible to inject dependencies in the render method.
class MyComponent extends Component
{
public string $search = '';
public function render(MyRepository $repo)
{
return view('livewire.my-component', [
'items' => $repo->getItems($this->search),
]);
}
}
Right now we're relying on resolving the dependencies using the IoC container directly.
@tonysm is there a problem injecting it into the mount() method?
@tomirons Yeah, that was our first attempt. But the dependency (even after assigning it to a private property) is only available for the first run of the component (when _mount_ is called), for subsequent renders the injected dependency is no longer available.
Edit: and we didn't try to assign it to a public property because it wasn't a piece of data we wanted to add some interactivity, so it didn't feel right. Not even sure if it would work for a service, tbh.
@tonysm yeah, for a class like that I wouldn't put it as a public property unless you wanted to use it in the template.
What about calling the $repo->getItems() in the controller and passing them as a prop to the component? This is a stretch but I have a feeling that you'll potentially want to use the repository during other methods, right?
@tomirons that would technically work, but in the example I showed, I injected a repository and the search term is passed to the repository, for instance. The search term is the piece of dynamic data I want livewire to handle, and that is passed to the repository on every render. I couldn't pass the items to the component because the items are based on the search which is defined inside the component.
The way we are doing now is:
class MyComponent extends Component
{
public string $search = '';
public function render()
{
return view('livewire.my-component', [
'items' => resolve(MyRepository::class)->getItems($this->search),
]);
}
}
I was just thinking if there wasn't a better way to do something like this.
@tonysm unless there is a going HUGE performance increase I don't see a problem with the way you have it now other than personal preference/cleanliness.
It's not personal preference. It's good coding practices.
It's not personal preference. It's good coding practices.
I second @mkarnicki statement. Also nothing else is passed to render.
Cannot say anything about performance thought. As in - I have no clue.
What about calling the
$repo->getItems()in the controller and passing them as a prop to the component? This is a stretch but I have a feeling that you'll potentially want to use the repository during other methods, right?
I just ran into this problem -- the issue with doing it in the controller is I need access to the page we're on (from WithPagination), and that's only available in the component.
I'd deffo like to see render permit injection.
Plus it will give you better IDE support. (over resolve() that is).

@var mixed
versus

@var YadaYada\Repository
I just wanted to know if I could work on a PR for that or if we shouldn't touch on the render method (for some reason) or if the render method is not a place for IoC bindings, don't know. You can still get autocompletion if you wrap the container resolution call in a private method and add a return type to it or using docblocks for the $repository variable if you really want to. :wink:
I use doc-blocks. But that's not for the cool kids @tonysm haha
I looked into what is needed yesterday. There is a trait that you can use for the resolving part. The bigger issue as I see it that Component has a render() method already. So all sub-classes would need the same signature. I guess you would have to remove that method and move the handing into __call where mount is dealt with.
I think you should go ahead with a PR. Would love to see this feature.
We have support for DI in ->render() on the roadmap for V2. (supporting it would be a breaking change)
For now, I believe you can DI inside of action methods, but you are welcome to just app(SomeClass::class) for now if you need to resolve out of the container.
Closing this for now.
Most helpful comment
It's not personal preference. It's good coding practices.