Most of the regular React API is integrated (like React.createElement
),
and the library uses a compile-time macro to parse JSX and generate
the same kind of code that Facebook's JSX, Babel and Typescript will.
import react.React;
import react.ReactDOM;
import react.ReactMacro.jsx;
import Browser.document;
class App extends ReactComponent {
static public function main() {
ReactDOM.render(
jsx('<App/>'),
document.getElementById('root')
);
}
override function render() {
var cname = 'it-bops';
return jsx('
<div className={cname}>
<h1>Hello React</h1>
</div>
');
}
}
Tips:
- JSX has limitations, check the gotchas below,
- Both classic JSX
{var}
binding and Haxe string interpolation are allowed:attr=$var
/${expression}
/<$Comp>
. String interpolation can help for code completion/navigation. - Spread operator and complex expressions within curly braces are supported.
Note: when writing externs, make sure to extend ReactComponent
@:jsRequire('react-redux', 'Provider')
extern class Provider extends ReactComponent { }
-
JSX must be a String literal! Do not concatenate Strings to construct the JSX expression
-
JSX parser is not "re-entrant"
In JavaScript you can nest JSX inside curly-brace expressions:
return ( <div>{ isA ? <A/> : <B/> }</div> );
However this isn't allowed in Haxe, so you must extract nested JSX into variables:
var content = isA ? jsx(<A/>) : jsx(<B/>); return jsx(<div>{content}</div>);
To control React features that should be enabled, depending on your target React version,
use -D react_ver=<version>
, like -D react_ver=16.3
if you want to restrict to 16.3
.
Otherwise all the features will be turned on:
react_fragments
: e.g<Fragment>
, since React 16.2react_context_api
: e.g.React.createContext
, since React 16.3react_ref_api
: e.g.React.createRef
, since React 16.3react_snapshot_api
: e.g.getSnapshotBeforeUpdate
, since React 16.3react_unsafe_lifecycle
: e.g.UNSAFE_componentWillMount
, since React 16.9
The default ReactComponent
type is a shorthand for
ReactComponentOf<Dynamic, Dynamic>
, a fully untyped component.
To benefit from Haxe's strict typing you should look into extending a stricter base class:
class ReactComponentOf<TProps, TState> {...}
typedef ReactComponentOfProps<TProps> = ReactComponentOf<TProps, Empty>;
typedef ReactComponentOfState<TState> = ReactComponentOf<Empty, TState>;
The Empty
type is an alias to {}
, which means:
ReactComponentOfProps
can NOT use any state,ReactComponentOfState
can NOT use any props.
componentDidUpdate
exceptionally doesn't need to be overriden with all its
parameters, as it's common in JS to omit or add just what is needed:
since React 16.3 you should normally exactly override the function as:
override function componentDidUpdate(prevProps:Props, prevState:State, ?snapshot:Dynamic):Void {
// ugh :(
}
override function componentDidUpdate() {
// nicer, and valid!
}
By default, when building for release (eg. without -debug
), calls to React.createElement
are replaced by inline JS objects (if possible).
See: facebook/react#3228
// regular
return React.createElement('div', {key:'bar', className:'foo'});
// inlined (simplified)
return {$$typeof:Symbol.for('react.element'), type:'div', props:{className:'foo'}, key:'bar'}
This behaviour can be disabled using -D react_no_inline
.
Setting -D react_runtime_warnings
will enable runtime warnings for avoidable renders.
This will add a componentDidUpdate
(or update the existing one) where a
shallowCompare is done on current and previous props and state. If both did
not change, a warning will be displayed in the console.
False positives can happen if your props are not flat, due to the shallowCompare.