Video: Haxe and React using create-react-app workflow

Hi!

Just published a video introduction on how to integrate Haxe into a React create-react-app workflow. Includes using benmerckx’s watch library for auto-compiling the Haxe code, and using haxiomic’s dts2hx library for generating Haxe externs from third-party react libraries. Brief introductions on how to use functional components including hooks, as well as class-based components - all in a typesafe manner.

/ Jonas

15 Likes

Hey, nice! Definitely easier to get started with haxe + react this way :slight_smile:

Couple notes:

You might want to check React.createRef() for easier refs (and don’t ignore null values sent to your ref callback, it usually means your component unmounted, and you don’t want to keep an outdated reference).

Also, careful with “type safety” here; you don’t really have it in several places (hooks, context, and even props on the jsx side).

1 Like

It’s probably worth mentioning react-next for increased type safety in jsx (although I can’t fully comment on how far it goes these days).

As for hooks, I don’t see why they would not be typed. It is however true that the dependencies array is not statically checked, as it is with eslint/tslint in create-react-app’s setup. From my own experience, that’s not necessarily a down side though :smiley:

It’s probably worth mentioning react-next for increased type safety in jsx (although I can’t fully comment on how far it goes these days).

Yeah… but I don’t think it would work as well with dts2hx because of that =/

As for hooks, I don’t see why they would not be typed.

Yeah it depends how you write them, I double checked the video and it was fine I suppose

thanks for this great tutorial but i have some problem using react.ReactComponent here are the error messages:
workspaces/shirase/apps/testreact/src-hx/import.hx:4: characters 8-28 : Type not found : react.ReactComponent
/workspaces/shirase/apps/testreact/src-hx/import.hx:5: characters 8-24 : Type not found : react.ReactMacro
/workspaces/shirase/apps/testreact/src-hx/import.hx:9: characters 8-23 : Type not found : szhin.ReactMenu
/workspaces/shirase/apps/testreact/src-hx/import.hx:10: characters 8-23 : Type not found : szhin.ReactMenu
/workspaces/shirase/apps/testreact/src-hx/import.hx:11: characters 8-23 : Type not found : szhin.ReactMenu
src-hx/Index.hx:4: characters 8-28 : Type not found : react.ReactComponent
src-hx/Index.hx:5: characters 8-24 : Type not found : react.ReactMacro
/workspaces/shirase/apps/testreact/src-hx/import.hx:4: characters 8-28 : Type not found : react.ReactComponent
/workspaces/shirase/apps/testreact/src-hx/import.hx:5: characters 8-24 : Type not found : react.ReactMacro
/workspaces/shirase/apps/testreact/src-hx/import.hx:9: characters 8-23 : Type not found : szhin.ReactMenu
/workspaces/shirase/apps/testreact/src-hx/import.hx:10: characters 8-23 : Type not found : szhin.ReactMenu
/workspaces/shirase/apps/testreact/src-hx/import.hx:11: characters 8-23 : Type not found : szhin.ReactMenu
src-hx/react/ReactHooks.hx:5: characters 8-19 : Type not found : react.React
src-hx/react/ReactHooks.hx:13: characters 40-55 : Type not found : ReactContext

here is my code https://github.com/araneta/shirase/tree/main/apps/testreact
how to fix this?
Thanks

Hi araneta!

It seems that something in the dts2hx process has changed, probably to a new version of @szhsin-react-menu, so that dts2hx now creates completel new react externs. Have a look into .haxlib/react/ folder, there’s a 17.0.27 foldler, probably created by dts2hx. That’s what’s causing the Type not found: react.ReactComponent problem, if I’m not mistaken…

You can switch back to the original haxelib version by changing the content of the text file .haxelib/react/.current to 1.12.0.

So that solves half of the problem - the szhsin externs won’t work now, because they are refering to the newer 17.0.27 version…

Creating externs manually for React components actually isn’t that hard. Here’s a quick example:

// ReactMenu.hx
// Drop this file into your your haxe project src folder

@:jsRequire('@szhsin/react-menu')
extern class ReactMenu {
	static function useMenuState(?options:ReactMenuStateOptions):{
		@:optional
		var state:ReactMenuState;
		dynamic function toggleMenu(?open:Bool):Void;
		dynamic function endTransition():Void;
	};

	static final MenuButton:Dynamic;
	static final Menu:Dynamic;
	static final ControlledMenu:Dynamic;
	static final SubMenu:Dynamic;
	static final MenuItem:Dynamic;
	static final FocusableItem:Dynamic;
	static final MenuDivider:Dynamic;
	static final MenuHeader:Dynamic;
	static final MenuGroup:Dynamic;
	static final MenuRadioGroup:Dynamic;
	// static function applyHOC<H>(hoc:H):H;
	// static function applyStatics<W>(sourceComponent:Dynamic):(w:W) -> W;
}

typedef ReactMenuStateOptions = {
	@:optional
	var initialMounted:Bool;
	@:optional
	var unmountOnClose:Bool;
	@:optional
	var transition:Dynamic;
	@:optional
	var transitionTimeout:Float;
};

typedef ReactMenuState = String;

Then you can use it like this:

import react.ReactMacro.jsx;
import ReactMenu.MenuItem;
import ReactMenu.MenuButton;
import ReactMenu.Menu;
import js.Browser.alert;

function TestMenuHx() {
js.Lib.require('@szhsin/react-menu/dist/index.css');
var menuButton = jsx('<MenuButton>ClickMe</MenuButton>');
return jsx('<div>    
	<h1>TestMenuHx</h1>
	<Menu menuButton=${menuButton}>
		<MenuItem>New File</MenuItem>
		<MenuItem onClick=${e -> alert('Hello')}>Save</MenuItem>
	</Menu>        
	</div>');
}

Note that you then don’t need the -L szhsin-react-menu flag in your build.hxml file.

Hope this helps!

I tried to compile this code in other computer but i got this error:
$haxe build.hxml
the error is
src-hx/Index.hx:10: characters 1-9 : Unexpected function
what should i do?

the content of Index.hx is

import js.Browser.document;

import react.ReactDOM;
import react.ReactComponent;
import react.ReactMacro.jsx;
import react.ReactHooks;

//import react_loadable.Loadable;

function main(){
    trace('elodas');
    ReactDOM.render(jsx('<div><h1>dasdas</h1> <Greeting greeter=
    "Luci" />
    <ClickCounter />
    <TestComponent name="bob" age=${33} />
    </div>'), document.getElementById('root'));
}

function Greeting(props: {greeter: String}) return jsx('<h2>Hello, ${props.greeter}!</h2>');

function ClickCounter(){
	var counts = ReactHooks.useState(0);
	return jsx('<button onClick=${e->counts.value = counts.value +1}>${counts.value} counts</button>');
}

What version of Haxe are you using?

version 4.0.5
haxe --version
4.0.5

You need at least 4.2.0 to use module level functions. Before that version you need a class around your functions, which in this example will also need to be declared as static.

how to upgrade the haxe version, i’m using linux mint 20. Thanks for your help

You can have a look at lix-pm, which helps to install and version your project dependencies : haxe version, libraries (from haxelib, github…). It allows your project to be portable across computers and through time because it locks the libs’ and haxe versions your required, and install them if needed.

Part of it is an “haxe installer”, so you can use the version you want for your project, without manually installing it globally or relying on your system’s packaged version. The readme describes well how to get started.

1 Like

thank you so much i will try it