I have been developing a web application in Seaside+Squeak recently, and have found it to be a wonderful experience. Seaside really is head and shoulders above every other framework out there, and I feel as though I am working at a higher level of abstraction (above the HTTP request/response cycle and HTML templating that other frameworks make you deal with).
That said, I'm a little confused about Seaside components. I recently had to display a list of objects on a component (similar to the stackoverflow front page). At first I made each object a component (a subclass of WAComponent), but this proved to be really wasteful, and I had to set #children dynamically in the parent component for it to work at all. I then tried making them render objects (objects that aren't subclasses of WAComponent, and render using renderOn: instead of renderContentOn:, like components do). This worked, but now they could no longer access global state in the session object as components can (using #session). Then I discovered "WACurrentSession value", which gives any object access to the current Seaside session object. I was now able to make them render objects. In addition, I discovered that I could rewrite a lot of my other, more minor components as render objects, too.
Besides needing call/answer or backtracking state, what other reasons are there for using components over render objects?
This is a frequent point of confusion for new Seaside users. We have tried hard to make this clearer in Seaside 2.9, which is currently in Alpha, but I will try to focus on 2.8 here since it sounds like that is what you are using.
First of all, you are correct that you do not need to use a Component in order to access the Session. Seaside 2.9 moves #session
up to a new class WAObject
which makes it accessible to almost all Seaside objects (including Components) but you can definitely refer to WACurrentSession
yourself for now in 2.8.
Components provide roughly the following functionality in 2.8:
#renderContentOn:
is called with an instance of whatever renderer class you specify in #rendererClass
(instead of whatever renderer is in use when your object is asked to render itself)#updateUrl:
) to allow updating the URL used by the renderer to generate links#updateRoot:
, #style
, #script
) to allow updating the HEAD section of the HTML document#updateStates:
, #states
) to make state backtracking easier#initialRequest:
) to allow initialization based on the request that caused the Session to be created#children
) to make sure all components below you will also have the above hooks called on them#inform:
, #isolate:
, etc)If you don't need any of the above, you don't need a Component. If you need any of the above, you pretty much do need a Component unless you want to implement the equivalent functionality on your own class.
The simplest metric is probably: if you intend to keep the object around between HTTP requests it should be a Component; if you intend to throw the object away and create it on each rendering pass it probably doesn't need to be. If you imagine an application that was displaying blog pages, you'd probably have Components for a menu, a blog roll, the blog body, each comment, and so on. You might want to factor out the reading of the blog's markup and generation of its HTML so that you could support different markups or different renderers and so that the comment Components could support the same markup. This could be done with a non-Component class that implements #renderOn:
and could be created and used by other Components as needed.
Seaside 2.9 currently splits up the above functionality by making WAPresenter
concrete and introducing WAPainter
as its superclass. 1-3 above are implemented on WAPainter
and 4-7 on WAPresenter
so you have your choice of what to subclass depending on your needs. It also removes a lot of methods from WAPresenter and WAComponent in an effort to make them easier for end users to understand.
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With