MXML
The MXML language, as part of the Apache Flex framework, was used for describing UI components in an intuitive way. ShockScript uses XML expressions semantically similiar to the React.js + JSX technologies, but designed to feel close to MXML in readability.
The following demonstrates a basic UI component implemented in WhackDS:
package com.business.components {
//
public function AppBar():whack.ds.Node {
return (
<w:HGroup>
<w:Button click&={trace("clicked!")}>button 1</w:Button>
</w:HGroup>
);
}
}
Event handlers
In MXML, event handlers were expressed as e="statements". In ShockScript, they are expressed as e&={statements} (note the ampersand &) as a shorthand to e={function(event){statements}}.
Note: Although not demanded as such, as opposed to React.js + DOM, event handlers are conventionally expressed without a
onprefix, such asclick&={trace("clicked!")}rather than React.jsonClick={e=>{console.log("clicked!")}}. Event parameters are conventionally given the@eventparamtag in the ShockDoc comments. Classes continue using theEventmeta-data, though without needing the@eventTypetag.
Rendering components
The Whack Engine's WhackDS feature allows programmers to implement UI components as functions that wrap around the built-in class-based components of Whack Engine. The component is rendered by evaluating the function initially and whenever a state changes.
Effects
The whack.ds.useEffect hook may be used to detect state, parameter or derived changes as well as the component mount and unmount phases.
whack.ds.useEffect(function() {
// cleanup
return function() {
//
};
}, [dep1, ...depN]);
whack.ds.useEffect(function() {
//
}, "*");
When the dependencies list is empty ([]), the hook is equivalent to a component mount/unmount event, with the unmount phase handled through the returned function.
whack.ds.useEffect(function() {
// did mount
return function() {
// unmount
};
}, []);
States
In the top-level of a component, declare states using the State meta-data:
[State]
var counter:uint = 0;
The initial value of counter is zero, although that initializer evaluates only the first time the component renders.
Overwriting a state with a different value (as by an .equals() comparison) will re-render the component.
Note that, like with React.js, arrays and structures as states will not trigger a re-render on operations like .push(); instead the programmer needs to reconstruct the array or structure, like in:
list = [...list, v];
Bindables
In the top-level of a WhackDS component, declare bindables by using the Bindable meta-data. Bindables have certain use-cases, such as persisting a value across renders, and extracting class-based components from certain tags (in which case the bind attribute is used).
[Bindable]
var button:Button? = null;
return (
<w:Button bind={button}>click me</w:Button>
);
Contexts
In the top-level of a component, reflect inherited contexts by using the Context meta-data.
[Context("ThemeContext")]
const theme;
Capture safety
Unlike in React.js combined with TypeScript, states, bindables ("refs") and context values are captured by reference from nested functions, guaranting the "outdated" value of, say, a state, is never captured, which facilitates development by requiring no additional bindable declaration.
Styling
Unlike with React.js, there is built-in support for linking style sheets in a WhackDS component.
<w:Group>
<w:Style>
<![CDATA[
:host {
background: red;
}
]]>
</w:Style>
</w:Group>