dojo dragon main logo

Best practice development

When working with Dojo widgets, a few important principles should be kept in mind to avoid introducing anti-patterns into application code. Attempting to use the framework in an unsupported way can cause unexpected behavior and introduce difficult to find bugs into an application.

Widget properties

  • Widgets should treat the properties passed to them as read-only.
    • Changes made to received properties within a widget cannot be propagated back to the framework, and result in a divergence between the widget and the framework.
  • Widgets should avoid deriving further render state from their properties, and instead rely on their complete render state being provided to them.
    • Deriving render state can cause similar divergences between the widget and the framework as modifying received properties; the framework is not aware of the derived state, so cannot properly determine when a widget has been updated and requires invalidation and re-rendering.
  • Internal or private state can be fully encapsulated within a widget, if required.
    • It is a valid and often desirable pattern to implement 'pure' widgets that incur no side effects and receive their entire state as properties, but this is not the only pattern in Dojo widget development.

Using class-based widgets

  • The __render__, __setProperties__, and __setChildren__ functions are internal framework implementation details and should never be called nor overridden in application code.
  • Applications should not instantiate widgets directly - Dojo fully manages the lifecycle of widget instances, including instantiation, caching and destruction.

The virtual DOM

  • Virtual node keys should be consistent across multiple render calls.
    • If a different key is specified on every render invocation, Dojo cannot efficiently associate nodes across previous and current renders. Dojo treats new keys that it has not seen in the previous render as new elements, which results in the previous nodes being removed from the DOM and an entirely new set being added - even when there are no other property changes that would actually warrant a DOM update.
    • A common anti-pattern is assigning a randomly-generated ID (such as a GUID or UUID) as a node's key within a widget's render function. Node keys should not be generated within a render function unless the generation strategy is idempotent.
  • Applications should not store references to virtual nodes for later manipulation outside of returning them from a widget's render function, nor as an attempt to optimize memory allocation by using a single instance across multiple render calls.
    • Virtual nodes are designed to be lightweight and cost very little to instantiate new versions of within every widget render cycle.
    • The framework relies on having two separate virtual node instances across two widget render function calls to perform accurate change detection. If no changes are detected, no further cost is incurred, rendering or otherwise.

Rendering and the DOM

  • Applications should have no need to use imperative DOM manipulation calls.
    • The framework handles all concrete rendering responsibilities, and provides alternative mechanisms to widget authors for using a variety of DOM functionality in a more simplified, type-safe, and reactive manner.