Interop with React
November 3, 2018 ยท View on GitHub
In the prior chapter, we learned how to update an existing audio graph whenever a HTMLInputElement fires a change event. Can we handle the visual UI with React while supporting JSX-declared audio graphs with Wax?
The problem is that we need to be able to use React.createElement and createAudioElement at the same time. What if we could compose a single pragma that can select whether to use the former or the latter at runtime? The withReact example app has a solution:
/** @jsx createElement */
import {
isWaxComponent,
...
} from 'wax-core';
import combineElementCreators from './combineElementCreators';
const createElement = combineElementCreators(
[isWaxComponent, createAudioElement],
[() => true, React.createElement],
);
combineElementCreators is a function that takes a mapping between predicates and pragmas, and returns a new pragma to be targeted by our transpiler. In our example, if an element belongs to Wax (determined using the exposed isWaxComponent binding), then the createAudioElement pragma will be invoked; otherwise, we'll default to React.createElement. combineElementCreators isn't provided by Wax but can be implemented with a few lines of code:
const getCreator = (map, Component) =>
[...map.entries()]
.find(([predicate]) => predicate(Component))[1];
const combineElementCreators = (...creatorBindings) => {
const map = new Map(creatorBindings);
return (Component, props, ...children) => {
const creator = getCreator(map, Component);
return creator(Component, props, ...children);
};
};
We can then instruct Babel to target this pragma in the usual way:
{
"presets": [
["@babel/react", {
"pragma": "createElement"
}]
]
}
The aforementioned withReact example demonstrates how ReactDOM.render and renderPersistentAudioGraph can be used across a single app.