Sunday, 19 October 2014

Declaring Seaside sub-components in the #children method

People often ask why they need to define the #children method on Seaside components. I wrote a long email today to the mailing list explaining how #children is currently used and why it's important and I thought it might be useful to post it here as well so it's easier to find and link to. 

When you render a child component you are implicitly defining a tree of components. #children simply allows the framework to walk the component tree explicitly. The reasons for needing to walk the tree explicitly have changed over time, which is part of the reason for the confusion.

At one point, for example, we used to walk the tree to give each component a chance to handle callbacks, so if your component wasn't in #children it would never even have seen its callbacks. That is no longer the case (which is actually a bit of a shame because decorations can no longer intercept them, but I digress).

If you look in the image for users of WAVisiblePresenterGuide and WAAllPresenterGuide, you will see the current cases where we need to traverse the tree:
  1. Calling #updateStates: for snapshotting/backtracking
  2. Calling #initialRequest: when a new session is started
  3. Executing tasks (they need to execute outside of the render phase to make sure the render phase does not have side effects)
  4. Calling #updateRoot:
  5. Calling #updateUrl:
  6. Displaying Halos for each component in development mode
  7. Generating the navigation path in WATree
  8. Detecting which components are visible/active to support delegation (#call:/#show:)
Keep in mind that basically all these things happen before rendering, so if you create new components inside #renderContentOn: they'll miss out: you should try to create your sub-components either when your component is initialized or during a callback. If your child component doesn't rely on any of the above (and doesn't use any child components itself that rely on any of these things) then technically everything will work fine without adding it to #children. But keep in mind that:
  • the framework may change in the future to traverse the tree for other reasons;
  • add-ons may depend on being able to walk the tree for other reasons; and
  • it's not great encapsulation to assume that, in the future, components you are rendering will never need any of the above nor start using sub-components that do. 
Finally, components are stateful by definition, so if you don't feel the need to persist your component between render phases, it probably shouldn't be a component. For stateless rendering you're better to subclass WAPainter directly or even WABrush: both of these are intended to be used and then thrown away and they will make it clearer in your mind whether or not you're using on things that depend on #children.


Willie Ames said...

I feel that with each new frontend framework, the amount of javascript code is increasing and increasing, to the point that, if I have a medium to large-sized application, my (pipelined) application.js may have a few hundreds of KBs. I'm now starting a new app using React, and with only a single CRUD it already has over 200 lines of React code defining some components. Should I only require these component files, and also any other javascript file that's not global, on the specific pages such as purevpn review where they are being used?

Pamela Bryant said...

Informative article. A virtual private network, or just VPN, helps encrypt and secure your router against information theft, misuse and only fraud. A single DDWRT router VPN can protect traffic that is internet most of the networked computers, hence helping you save a huge expense for internet security and privacy. Furthermore, Purevpn will redress individual IPs also of every computer or device on the community, therefore helping you secure identities of computer on the World Wide Web.