Tech stack for mobile apps with Haxe, Redux and React native
While implementing applications with React native, you will often need to use some extra npm libraries that bring some native module, js lib or UI component you need in your app.
Doing so when you code your app with Haxe (vs ES6) is not a problem, but requires one extra step to keep the advantages of using Haxe in a type safe way: writing the Haxe “externs” of the lib you want to add.
It’s more or less the equivalent of writing a type definition with Typescript, except that with Haxe, you can do better (if you want to) by e.g. defining an API for this lib that will better fit to the Haxe language or to your app use case.
You have plenty examples of Haxe externs you can look at for inspirations, from very sophisticated ones like haxe-react, to straight and trivial ones like haxe-react-native-navigation.
Here we will just explain the basics of writing what we could just call a type definition, ie: some extra typing .hx
file that does not change the original API of the lib we add.
To illustrate that, let’s take the example of some random and simple lib for react we could find on GitHub: react-tabs.
When starting to write an extern, you will generally:
js.react.native.
), because you are just trying the lib and you are not sure to keep it, or just because it’s just some little lib which extern file just takes 1 minute to write.In this example, we will be in the latter case.
One thing also to check before writing your extern:
.ts
type definition file? If it’s the case, just convert it to Haxe, you will save time!In our case, the lib API looks like that:
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import "react-tabs/style/react-tabs.css";
export default () => (
<Tabs>
<TabList>
<Tab>Title 1</Tab>
<Tab>Title 2</Tab>
</TabList>
<TabPanel>
<h2>Any content 1</h2>
</TabPanel>
<TabPanel>
<h2>Any content 2</h2>
</TabPanel>
</Tabs>
);
and
import { resetIdCounter } from 'react-tabs';
resetIdCounter();
ReactDOMServer.renderToString(...);
We thus have at least 4 React components from that lib, plus some pure js API (resetIdCounter()
).
Let’s start with the React components:
src/js/react/tabs
.Tabs.hx
file with the following content:package js.react.tabs; // matches our src folder structure
import react.ReactComponent;
typedef TabsProps = {
?selectedIndex:Int,
?selectedTabClassName:String,
?selectedTabPanelClassName:String,
?onSelect:Int->?Int->?js.html.Event->?Bool, // check https://api.haxe.org/js/html/Event.html
?className:String,
?defaultFocus:Bool,
?defaultIndex:Int,
?disabledTabClassName:String,
?domRef:js.html.Element->Void, // check https://api.haxe.org/js/html/Element.html
?forceRenderTabPanel:Bool,
}
// here, we define an external React component which accepts props typed as TabsProps
@:jsRequire('react-tabs','Tabs')
extern class Tabs extends ReactComponentOfProps<TabsProps> {}
@:jsRequire('react-tabs','Tab')
extern class Tab extends ReactComponent {} // we do not type its props for now
@:jsRequire('react-tabs','TabList')
extern class TabList extends ReactComponent {} // we do not type its props for now
@:jsRequire('react-tabs','TabPanel')
extern class TabPanel extends ReactComponent {} // we do not type its props for now
@:jsRequire('react-tabs')
extern class ReactTabs {
static public function resetIdCounter() : Void;
}
import js.react.tabs.Tabs;
import api.react.React;
import api.react.ReactDOM;
import api.react.ReactMacro.jsx;
class MyApp extends ReactComponent {
static public function main(){
ReactDOM.render(React.createElement(MyApp), document.getElementById('app'));
}
override function render(){
return jsx('
<Tabs>
<TabList>
<Tab>Title 1</Tab>
<Tab>Title 2</Tab>
</TabList>
<TabPanel>
<h2>Any content 1</h2>
</TabPanel>
<TabPanel>
<h2>Any content 2</h2>
</TabPanel>
</Tabs>
');
}
}
Check out the samples to see more externs in both ReactJs and React Native contexts.
Writing good externs requires some practice. The more you will use Haxe with external libs, the better you’ll setup your externs.
Here are the ressources you should checkout to improve your extern skills: