Skip to content

Commit 2fa7b85

Browse files
author
Philippe Elsass
committed
Readme update
1 parent 024988c commit 2fa7b85

5 files changed

+313
-257
lines changed

doc/hoc-wrap.md

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Wrapping your components in HOCs
2+
3+
You can use HOCs with your components by adding `@:wrap` meta.
4+
5+
Note: not compatible with `@jsxStatic` meta.
6+
7+
In JavaScript it may look like that:
8+
```javascript
9+
import React from 'react';
10+
import { withRouter } from 'react-router';
11+
12+
class MyComponent extends React.Component {
13+
render() {
14+
return (
15+
<p>Current path is {this.props.location.pathname}</p>
16+
);
17+
}
18+
}
19+
20+
// HOC wrap
21+
export default withRouter(MyComponent);
22+
```
23+
24+
In Haxe it will be:
25+
26+
```haxe
27+
import react.ReactComponent;
28+
import react.ReactMacro.jsx;
29+
import react.router.ReactRouter;
30+
import react.router.Route.RouteRenderProps;
31+
32+
@:wrap(ReactRouter.withRouter)
33+
class MyComponent extends ReactComponentOfProps<RouteRenderProps> {
34+
function render() {
35+
return jsx(
36+
'<p>Current path is ${props.location.pathname}</p>'
37+
);
38+
}
39+
}
40+
```
41+
42+
You can add multime `@:wrap` metas:
43+
44+
```haxe
45+
import react.ReactComponent;
46+
import react.ReactMacro.jsx;
47+
import react.React.CreateElementType;
48+
import react.router.ReactRouter;
49+
import react.router.Route.RouteRenderProps;
50+
51+
// combined props
52+
private typedef Props = {
53+
> RouteRenderProps,
54+
var answer: Int;
55+
}
56+
57+
@:wrap(ReactRouter.withRouter)
58+
@:wrap(uselessHoc(42))
59+
class MyComponent extends ReactComponentOfProps<Props> {
60+
61+
static function uselessHoc(value:Int) {
62+
return function(Comp: CreateElementType) {
63+
return function(props: Any) {
64+
return jsx('<$Comp {...props} answer=${value} />');
65+
};
66+
};
67+
}
68+
69+
function render() {
70+
return jsx('
71+
<p>
72+
Current path is ${props.location.pathname} and the answer is ${props.answer}
73+
</p>
74+
');
75+
}
76+
}
77+
```

doc/react-api-jsx.md

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# React API and JSX
2+
3+
Most of the regular React API is integrated (like `React.createElement`),
4+
and the library uses a compile-time macro to parse JSX and generate
5+
the same kind of code that Facebook's JSX, Babel and Typescript will.
6+
7+
```haxe
8+
import react.React;
9+
import react.ReactDOM;
10+
import react.ReactMacro.jsx;
11+
import Browser.document;
12+
13+
class App extends ReactComponent {
14+
15+
static public function main() {
16+
ReactDOM.render(
17+
jsx('<App/>'),
18+
document.getElementById('root')
19+
);
20+
}
21+
22+
override function render() {
23+
var cname = 'it-bops';
24+
return jsx('
25+
<div className={cname}>
26+
<h1>Hello React</h1>
27+
</div>
28+
');
29+
}
30+
}
31+
```
32+
33+
Tips:
34+
35+
- JSX has limitations, check the gotchas below,
36+
- Both classic JSX `{var}` binding and Haxe string interpolation are allowed:
37+
`attr=$var` / `${expression}` / `<$Comp>`.
38+
String interpolation can help for code completion/navigation.
39+
- Spread operator and complex expressions within curly braces are supported.
40+
41+
Note: when writing externs, make sure to `extend ReactComponent`
42+
43+
```haxe
44+
@:jsRequire('react-redux', 'Provider')
45+
extern class Provider extends ReactComponent { }
46+
```
47+
48+
### JSX gotchas
49+
50+
1. JSX must be a String literal!
51+
**Do not concatenate Strings** to construct the JSX expression
52+
53+
2. JSX parser is not "re-entrant"
54+
55+
In JavaScript you can nest JSX inside curly-brace expressions:
56+
```javascript
57+
return (
58+
<div>{ isA ? <A/> : <B/> }</div>
59+
);
60+
```
61+
62+
However this isn't allowed in Haxe, so you must extract nested JSX into variables:
63+
```haxe
64+
var content = isA ? jsx(<A/>) : jsx(<B/>);
65+
return jsx(<div>{content}</div>);
66+
```
67+
68+
## Feature flags
69+
70+
To control React features that should be enabled, depending on your target React version,
71+
use `-D react_ver=<version>`, like `-D react_ver=16.3` if you want to restrict to `16.3`.
72+
73+
Otherwise all the features will be turned on:
74+
75+
- `react_fragments`: e.g `<Fragment>`, since React 16.2
76+
- `react_context_api`: e.g. `React.createContext`, since React 16.3
77+
- `react_ref_api`: e.g. `React.createRef`, since React 16.3
78+
- `react_snapshot_api`: e.g. `getSnapshotBeforeUpdate`, since React 16.3
79+
- `react_unsafe_lifecycle`: e.g. `UNSAFE_componentWillMount`, since React 16.9
80+
81+
## Components strict typing
82+
83+
The default `ReactComponent` type is a shorthand for
84+
`ReactComponentOf<Dynamic, Dynamic>`, a fully untyped component.
85+
86+
To benefit from Haxe's strict typing you should look into extending a stricter base class:
87+
88+
```haxe
89+
class ReactComponentOf<TProps, TState> {...}
90+
typedef ReactComponentOfProps<TProps> = ReactComponentOf<TProps, Empty>;
91+
typedef ReactComponentOfState<TState> = ReactComponentOf<Empty, TState>;
92+
```
93+
94+
The `Empty` type is an alias to `{}`, which means:
95+
- `ReactComponentOfProps` can NOT use any state,
96+
- `ReactComponentOfState` can NOT use any props.
97+
98+
### Special case
99+
100+
`componentDidUpdate` exceptionally doesn't need to be overriden with all its
101+
parameters, as it's common in JS to omit or add just what is needed:
102+
since React 16.3 you should normally exactly override the function as:
103+
104+
```haxe
105+
override function componentDidUpdate(prevProps:Props, prevState:State, ?snapshot:Dynamic):Void {
106+
// ugh :(
107+
}
108+
109+
override function componentDidUpdate() {
110+
// nicer, and valid!
111+
}
112+
```
113+
114+
## Optimization
115+
116+
### JSX compiler: inline ReactElements
117+
118+
By default, when building for release (eg. without `-debug`), calls to `React.createElement` are replaced by inline JS objects (if possible).
119+
120+
See: https://github.com/facebook/react/issues/3228
121+
122+
```javascript
123+
// regular
124+
return React.createElement('div', {key:'bar', className:'foo'});
125+
126+
// inlined (simplified)
127+
return {$$typeof:Symbol.for('react.element'), type:'div', props:{className:'foo'}, key:'bar'}
128+
```
129+
130+
This behaviour can be **disabled** using `-D react_no_inline`.
131+
132+
## Warning for avoidable renders
133+
134+
Setting `-D react_runtime_warnings` will enable runtime warnings for avoidable renders.
135+
136+
This will add a `componentDidUpdate` (or update the existing one) where a
137+
**shallowCompare** is done on current and previous props and state. If both did
138+
not change, a warning will be displayed in the console.
139+
140+
False positives can happen if your props are not flat, due to the shallowCompare.

doc/react-dependency.md

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# React JS dependency
2+
3+
Haxe React doesn't automatically includes React.js.
4+
5+
There are 2 ways to link the React JS library:
6+
7+
## Require method (default)
8+
9+
By default the library uses `require('react')` to reference React JS,
10+
which means that you need to get into the `npm` and use `package.json`
11+
to manage your JS dependencies.
12+
13+
(1) use `npm` to install this dependency:
14+
15+
```bash
16+
npm init
17+
npm install react react-dom
18+
# or for a specific version
19+
20+
```
21+
22+
(2) and use a second build step to generate the JS "bundle", that is a
23+
single JS file including both your Haxe JS output and any npm libraries
24+
that it's refering to.
25+
26+
### Example using Browserify
27+
28+
```bash
29+
npm install browserify watchify
30+
# bundle once
31+
npx browserify haxe-output.js -o bundle.js
32+
# bundle automatically (and debug friendly)
33+
npx watchify haxe-output.js -o bundle.js --debug
34+
```
35+
36+
### Example using Webpack (without config)
37+
38+
```bash
39+
npm install webpack webpack-cli
40+
# bundle once
41+
npx webpack haxe-output.js -o bundle.js
42+
# bundle automatically (and debug friendly)
43+
npx webpack haxe-output.js -o bundle.js -w --mode development
44+
```
45+
46+
For a more complexe setup of Webpack + React, look at:
47+
48+
- https://github.com/elsassph/webpack-haxe-example/tree/react
49+
50+
## Global JS method
51+
52+
The other common method is to download or reference the standalone
53+
JS files of React JS in your HTML page. These JS files will declare
54+
React in the "global scope" of the browser.
55+
56+
```html
57+
<script src="//cdnjs.cloudflare.com/ajax/libs/react/16.3.2/umd/react.development.js"></script>
58+
<script src="//cdnjs.cloudflare.com/ajax/libs/react-dom/16.3.3/umd/react-dom.development.js"></script>
59+
```
60+
61+
In this casee you must compile with the following flag:
62+
63+
-D react_global
64+
65+
Look at `samples/todoapp` for an example of this approach.

doc/static-components.md

+3-15
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Static components can be expressed as static functions:
2121
class MyComponents {
2222
public static function heading(props:{children:String}) {
2323
return jsx('
24-
<h1>${props.content}</h1>
24+
<h1>{props.content}</h1>
2525
');
2626
}
2727
}
@@ -31,7 +31,7 @@ And used in your jsx like this:
3131
```haxe
3232
jsx('
3333
<div>
34-
<$MyComponents.heading>Hello world!</$MyComponents.heading>
34+
<MyComponents.heading>Hello world!</MyComponents.heading>
3535
3636
...
3737
</div>
@@ -45,7 +45,7 @@ component and only then change it into a static component for performance).
4545
## `@:jsxStatic` components
4646

4747
Since haxe-react `1.3.0`, you can use a special meta on any class to transform
48-
it into a static component in the eyes of the jsx parser:
48+
it into a static component in the eyes of the JSX parser:
4949

5050
```haxe
5151
private typedef Props = {
@@ -72,15 +72,3 @@ Which can be used in jsx just like any other component:
7272
</div>
7373
');
7474
```
75-
76-
### Using `@:jsxStatic` components outside jsx
77-
78-
Current implementation only works when calling your component inside jsx. It
79-
won't work if you use `Heading` where a `CreateElementType` is required. It
80-
still works, however, to use `Heading.myRenderFunction` there.
81-
82-
[PR #109](https://github.com/massiveinteractive/haxe-react/pull/109) improves
83-
`CreateElementType` (and renames it as `ReactNode` like in TypeScript), and
84-
adds such support. `@:jsxStatic` components can be used anywhere a `ReactNode`
85-
is needed, like any other component.
86-

0 commit comments

Comments
 (0)