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 Jet+Spot:
package com.business.components {
//
public function AppBar() {
return (
<j:HGroup>
<j:Button click&={trace("clicked!")}>button 1</j:Button>
</j: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
on
prefix, such asclick&={trace("clicked!")}
rather than React.jsonClick={e=>{console.log("clicked!")}}
. Event parameters are conventionally given the@eventparam
tag in the ShockDoc comments. Classes continue using theEvent
meta-data, though without needing the@eventType
tag.
Rendering components
The Jet Engine's Spot feature allows programmers to implement UI components as functions that wrap around the built-in class-based components of Jet Engine. The component is rendered by evaluating the function initially and whenever a state changes.
Effects
The Spot::useEffect
hook may be used to detect state, parameter or derived changes as well as the component mount and unmount phases.
Spot::useEffect(function() {
// cleanup
return function() {
//
};
}, [dep1, ...depN]);
Spot::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.
Spot::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 is only assigned to the state the first time the component renders.
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];
References
In the top-level of a component, declare references by using the Reference
meta-data. References 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).
[Reference]
var button:Button? = null;
return (
<j:Button bind={button}>click me</j:Button>
);
Contexts
In the top-level of a component, reflect inherited contexts by using the Context
meta-data.
[Context(ThemeContext)]
var theme:Theme;
Capture safety
Unlike in React.js combined with TypeScript, states, references and context reflections are captured by reference from nested functions, guaranteeing the "outdated" value of, say, a state, is never captured, which facilitates development by requiring no additional reference declaration.
Styling
Unlike with React.js, there is built-in support for linking style sheets in a Spot component.
<j:Container>
<j:Style>
<![CDATA[
:host {
background: red;
}
]]>
</j:Style>
</j:Container>