Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for Roact-like/Class-based components #265

Closed
nakoyasha opened this issue Jul 26, 2023 · 4 comments
Closed

Support for Roact-like/Class-based components #265

nakoyasha opened this issue Jul 26, 2023 · 4 comments
Labels
enhancement New feature or request

Comments

@nakoyasha
Copy link

nakoyasha commented Jul 26, 2023

Currently, functional components get pretty messy when you start adding a lot of functionality (ex. listening for a humanoid's health property to update an internal health value, etc)

I propose a Component class

local Fusion = require(Fusion)
local TestComponent = Fusion.Component()

function TestComponent:init()
--   [ initialize observers, internal states, etc here]
end

function TestComponent:render()
 --   [ return fusion code ]     
end

return TestComponent

It would be created the same-way as regular functional components and would return the rendered instance, as to be consistent with functional components

local InstanceComponent = TestComponent()

InstanceComponent.Parent = -- [ gui instance ]

Alternatively, could be created in the same way as Roact, via the New function

local InstanceComponent = Fusion.New(TestComponent)

There's a library that already does this but has a couple differences, but it'd still be nice to have a native implementation.

@nakoyasha nakoyasha added enhancement New feature or request not ready - evaluating Currently gauging feedback labels Jul 26, 2023
@Aimarekin
Copy link
Contributor

Aimarekin commented Jul 29, 2023

But Fusion doesn't really have a "render" stage, and "mounting" sounds like a bad practice that goes against the principles of Fusion, components should instead be directly placed into Children.

Really, wouldn't you just be making the same code, but in two separate functions for no real reason? Furthermore complicating the library by adding an unnecessary "Component" class

@nakoyasha
Copy link
Author

nakoyasha commented Jul 31, 2023

But Fusion doesn't really have a "render"

And it doesn't need one! init and render could be ran once when the component is created (as with regular functional components)

"mounting" sounds like a bad practice that goes against the principles of Fusion, components should instead be directly placed into Children.

There's no real "mounting" part here though? In the proposal I suggested that components should just return the rendered instance on creation.

Also, what do you mean by "components should instead be directly placed into Children"?

Really, wouldn't you just be making the same code, but in two separate functions for no real reason?

Unless there's some hidden feature in VSCode that I'm not aware of, with a class-based component you could just minimize the init function if it gets too big, and instead focus on the actual UI code, something you can't really get with functional components.

I guess it's also just syntax sugar.

@dphfox
Copy link
Owner

dphfox commented Aug 1, 2023

I don't really think this is necessary. From what I can gather, this is pretty much just creating an object then calling two methods on it right away, rather than providing some new expansion of what components can do. This is easily achievable in user code and does mean Fusion would impart a relatively significant opinion on user code without a strong motivation or value-add, which I'd like to avoid.

I'm more interested in use cases where you want to separate the existence of a component from the process of building its instances. What I mean by this is, for example, wanting to know what components exist in your UI so you can do custom layout, then build those instances with the placement from that layout. This is a use case I'm more actively interested in, and already have been playing around with prototypes of.

The idea here is that, instead of directly building instances, constructing a component would immediately construct and return a small, simple table, with a field storing the property table you passed in and a field referencing a table of methods shared between all components of that type.

Luau's type annotation system could then be used to define certain 'traits' that can be implemented, similar to Rust. The types define standard methods for performing actions such as building instances, calculating natural layout sizes, or querying for capabilities like input processing. The method tables can then implement methods from as many traits as required.

From there, users of components could then call into methods from that method table, and pass in the property table from the component, and you end up with a pretty lightweight semi-OOP component system.

I think this extension of components is better motivated and retains a good level of flexibility for users. We will probably need to revise terminology if this ever gets implemented, but it seems like it could be a genuine value-add and a good idea to standardise.

This may also help efforts in #263 because it explicitly decouples components from any sort of backend - it's entirely feasible you could share components across Luau environments by simply defining different traits on them. You could even render the same component in different ways within the same environment.

@dphfox
Copy link
Owner

dphfox commented Aug 1, 2023

On reflection and after some discussion in the OSS Discord, this seems like it starts to escape the scope of what's relevant for most Fusion codebases, so I think this sort of feature probably best belongs in an external library to target those users for whom it's relevant.

@dphfox dphfox closed this as not planned Won't fix, can't repro, duplicate, stale Aug 1, 2023
@dphfox dphfox added status: rejected and removed not ready - evaluating Currently gauging feedback labels Aug 1, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants