A Haxe library offering externs for version 4 of the react-router library. For version 3, see haxe-react-router by elsassph.
Compatibility with react-router
javascript lib:
0.1.X
=>4.2.X
0.2.X
=>4.3.X
Using haxelib:
haxelib install react-router-4
An extensive documentation is available here
for the javascript react-router
library and is mostly applicable for this library too.
This lets you use the same matching code that <Route>
uses except outside of
the normal render cycle, like gathering up data dependencies before rendering
on the server.
See https://reacttraining.com/react-router/web/api/matchPath
You can get access to the history object’s properties and the closest
<Route>
's match via the withRouter higher-order component. withRouter will
re-render its component every time the route changes with the same props as
<Route>
render props: { match, location, history }
.
See https://reacttraining.com/react-router/web/api/withRouter
With haxe-react
version 1.4.1+
(not released at the moment, but this is available by using the git version),
you can use @:wrap
to easily wrap your component with a withRouter
call:
@:wrap(react.router.ReactRouter.withRouter)
class MyComponent extends ReactComponentOfProps<Props> {
}
React Router components are available in the react.router
package.
Each component has its typed props with comments and a link to the javascript react-router
documentation,
which applies to this library.
List of available components:
react.router.Router
- Documentationreact.router.BrowserRouter
- Documentationreact.router.HashRouter
- Documentationreact.router.MemoryRouter
- Documentationreact.router.StaticRouter
- Documentationreact.router.Link
- Documentationreact.router.NavLink
- Documentationreact.router.Switch
- Documentationreact.router.Redirect
- Documentationreact.router.Route
- Documentationreact.router.Prompt
- Documentation
When using the webpack haxe-loader
library,
you can use react.router.bundle.Bundle.load(...)
to split your application into bundles directly in your routes:
import react.ReactMacro.jsx;
import react.router.BrowserRouter;
import react.router.Route;
import react.router.Switch;
import react.router.bundle.Bundle;
class MainRouter extends ReactComponent {
override public function render() {
return jsx('
<$BrowserRouter>
<$Switch>
<!-- Using default loader component (`<div className="loader" />`) -->
<!-- and default error component (`<div className="error" />`) -->
<!-- /!\\ Warning: your component should have the `@:expose("default")` meta -->
<!-- See example below in "Bundle initialization code" -->
<$Route
path="/bundle1"
component=${Bundle.load(first.FirstBundle)}
/>
<!-- Using custom loader and/or error component -->
<!-- The error component will get an `error` prop with the load error as `Dynamic` -->
<$Route
path="/bundle2"
component=${Bundle.load(second.SecondBundle, CustomLoader, CustomError)}
/>
</$Switch>
</$BrowserRouter>
');
}
}
See the @:jsxStatic
original PR on haxe-react if you don't know about @:jsxStatic
components. Documentation will be added on haxe-react
later.
You cannot directly load @:jsxStatic
components with current (1.4.0
) haxe-react version.
There is a merged PR to make it work.
This is not released at the moment, but until 1.4.1+
you can use git version of haxe-react
.
If you really need to, another workaround is to use a wrapper around your @:jsxStatic
component:
// In your router
jsx('
<$Route path="/bundle3" component=${Bundle.load(MyWrapper)} />
');
// In your bundle's module
class MyWrapper extends ReactComponent {
override public function render() {
return jsx('
<$MyComponent {...props} />
');
}
}
@:jsxStatic('render')
class MyComponent {
public static function render(props:Dynamic) {
return jsx('<div>My component</div>');
}
}
You may want to execute some code when your bundle is first loaded.
When your component is loaded via Bundle.load(...)
(or ILazyLoad
, see below), you can define
initialization code to be executed at first load by creating an onLoad
static method on your component:
Adding @:expose('default')
should be optional with version 0.0.7+
, but you
should continue to add it, especially if you are using other libraries using
split bundles.
import react.ReactComponent;
import react.router.Route.RouteRenderProps;
@:expose('default')
class MyBundle extends ReactComponentOfProps<RouteRenderProps> {
// If you want to execute code when this bundle is _first_ loaded:
public static function onLoad() {
// ...
}
// ...
}
If you use custom loaders and/or custom error components, Bundle.load()
calls can become quite verbose.
There is an experimental API based on macros to define your async routes like this:
import react.ReactMacro.jsx;
import react.router.BrowserRouter;
import react.router.Route;
import react.router.Switch;
import react.router.bundle.ILazyLoad;
// Magic interface with build macro
// To easily create component bundles
class LazyLoad implements ILazyLoad<[
my.first.app.FirstApp,
my.second.app.SecondApp,
my.third.app.ThirdApp
]> {
// A build macro will create 3 static functions:
// - FirstApp, which will render my.first.app.FirstApp
// - SecondApp, which will render my.second.app.SecondApp
// - ThirdApp, which will render my.third.app.ThirdApp
// Warning: due to this notation, you cannot lazy load two components with
// the same name from two different packages.
// You can also define a loader component, if you want
// If you don't, a <div className="loader"></div> will be rendered instead.
static var loading = my.components.Loader;
// Same thing for the error component.
// Both loaderComponent and errorComponent can be either a static var or a
// static function.
// The error component will receive an `error` prop with the load error.
// If you don't provide any, a <div className="error"></div> will be
// rendered if the require fails.
static function error() {
return jsx('<div className="error">Error!</div>');
}
}
You can then use them in your react-router routes:
class MyRouter extends ReactComponent {
override public function render() {
return jsx('
<$BrowserRouter>
<$Switch>
<$Route path="/first" component=${LazyLoad.FirstApp} />
<$Route path="/second" component=${LazyLoad.SecondApp} />
<$Route path="/third" component=${LazyLoad.ThirdApp} />
</$Switch>
</$BrowserRouter>
');
}
}