Comments (19)
You can further improve it by writing some macros to insert the __init__
function like:
@:build(ReactReduxMacro.connect(TodoList))
class VisibleTodoList {
static function mapStateToProps(state) {
return {...}
}
static function mapDispatchToProps(dispatch) {
return {...}
}
}
class ReactReduxMacro {
public static function connect(e:Expr) {
var cls = Context.getLocalClass().get();
return Context.getBuildFields().concat([{
access: [AStatic],
name: '__init__',
kind: FFun({
args: [],
expr: macro untyped $i{cls.name} = js.Lib.require('react-redux').connect(mapStateToProps, mapDispatchToProps)($e),
ret: null,
}),
pos: Context.currentPos(),
}]);
}
}
from haxe-react.
I hope you realize that <${MyComp.redux()} />
(besides the syntax) is a terrible thing to do: the ReactRedux.connect
function creates a whole new class extending MyComp
. See http://github.com/reactjs/react-redux/blob/master/src/components/connect.js
You would end up creating a whole new class every time your render
function runs.
That's the reason why the recommended pattern in JS is to completely replace MyComp
with the new class that connect
creates. But this pattern would be very difficult to use in Haxe because of the way classes are generated in some cases.
I didn't check what ReactIntl.injectIntl
does but I've seen an example where they wrap a "pure render" function (stateless component) and you are suggesting that it could wrap also a class like ReactRedux.connect
does.
Finally for the sake of exhaustivity, I've seen HOCs adding functions to the class prototype instead of extending the component with a new class. This is also pretty hard to support in typed languages.
A pattern that seem to work is:
class MyComp {
static public var Connect = ReactRedux.connect(mapStateToProps)(MyComp);
...
}
Which you would use as: <MyComp.Connect/>
.
That is nicely compatible with Haxe and easy to write manually. Potentially you could come up with a macro generating such Connect
property.
from haxe-react.
Or... it should be up to the ReactRedux (or any other lib) extern to define its hoc factory metadata itself... That probably preferable as it would maybe allow a better checking from the compiler...
from haxe-react.
Some cases HOCs would difficult to reconcile with Haxe I think.
- stateless function renderers would be simple enough but the macro generator doesn't support them,
- old-school mixins mess would be tricky to solve using Haxe typesystem,
- definition of custom classes (connect I think?) might work if es6 classes can extend Haxe ones. But then it might still be tricky to handle the necessary JS code generation for it.
The first step is to figure what Haxe code should be generated for such cases. Eg. if it's possible to write manually, then it can be generated using a macro - otherwise it's likely that it's not possible.
from haxe-react.
Hi there!
I do not understand all what you wrote... Maybe because I was not clear myself.
I'll try to sumarize the issue:
The HOC factories actually only inject logic/objects in the component props. No mixin here nor extension nor anything else...
When you do var MyReduxAwareComp = ReactRedux.connect(mapStateToProps)(MyComp)
, it actually only injects additional data or functions/callbacks in the props of MyComp to give MyReduxAwareComp.
The first step is to figure what Haxe code should be generated for such cases. Eg. if it's possible to write manually, then it can be generated using a macro - otherwise it's likely that it's not possible.
Yep, that makes sense to me.
So, if we stick to the ReactRedux example, here is what I currently do (and it works of course):
MyComp.hx:
typedef MyCompProps {
data : Array<String>
}
class MyComp extends ReactComponentOf<MyCompProps, Dynamic, Dynamic> {
static function mapStateToProps(state : Dynamic) {
return {
data: state != null ? state.data : []
}
}
static public function redux() : Dynamic {
return ReactRedux.connect(mapStateToProps)(MyComp);
}
override function render() {
// (...)
}
}
App.hx
class App {
static public function main() {
ReactDOM.render(jsx('
<${MyComp.redux()} />
'),
js.Browser.window.document.body);
}
}
It would be great to have some nicer syntax that does not require to write this: <${MyComp.redux()} />
but this <MyComp />
.
Is it clear to you? How would you see this with a macro/metadata/... ?
Note that the ReactRedux.connect factory is the most complex HOC factory I've seen until now. Usually, it's just a normal function that just takes your comp as parameter like this one:
class MyComp extends ReactComponentOf<Dynamic, Dynamic, Dynamic> {
static public function intl() : Dynamic {
return ReactIntl.injectIntl(MyComp);
}
// (...)
}
Note also that we need a system that allows "hoc factory chaining" on a single comp (some comp need to be passed through several different HOC factories to let them get features from several libs).
from haxe-react.
I hope you realize that <${MyComp.redux()} /> (besides the syntax) is a terrible thing to do: the ReactRedux.connect function creates a whole new class extending MyComp. See http://github.com/reactjs/react-redux/blob/master/src/components/connect.js
You would end up creating a whole new class every time your render function runs.
Gosh! Thanks for pointing this me out :s!
ReactIntl.injectIntl() also returns a wrapping component... I believe it will be the case most of the time with HOC factories...
Finally for the sake of exhaustivity, I've seen HOCs adding functions to the class prototype instead of extending the component with a new class. This is also pretty hard to support in typed languages.
I have not seen that yet. Also is this compatible with ES6? I haven't learnt ES6 yet but given that mixins are not possible with ES6, I would suspect this way of designing HOC factories would not work with ES6... If that's the case, we could consider this use case of HOC factories to be invalid and thus not support it...
A pattern that seem to work is:
class MyComp {
static public var Connect = ReactRedux.connect(mapStateToProps)(MyComp);
...
}
Which you would use as: <MyComp.Connect/>.That is nicely compatible with Haxe and easy to write manually. Potentially you could come up with a macro generating such Connect property.
Yep, I agree it's the simplest and cleanest way so far... If it was just to generate this and nothing else, I think no macro is needed here...
However, maybe we could think of a macro that would:
- generates this above,
- extends the MyComp original props with the ones added by Redux (in this example)
So that in only one statement (a metadata actually) we enforce the Redux additional props to the MyComp props and "connect" it...
Or maybe that's not a good idea and it has not such a great value that it would require the pain of working on a macro for that...
What do you think?
from haxe-react.
You can still modify the prototype in ES6, and do mixins "manually". There just isn't a way using the class Foo extends Bar
syntaxic sugar.
extends the MyComp original props with the ones added by Redux (in this example)
How do you know which props to add? I think you should just define those props as expected by your component even if it wasn't connected through redux.
Generally you want to avoid defining new types - it's badly handled by IDEs unless they are indirectly accessed.
from haxe-react.
@elsassph Maybe with the help of a custom js generator it'd be possible? It'd be pretty hardcore to do and maintain though. Not sure if worth it.
from haxe-react.
A custom JS generator would make the redux MyComp = connect(mapStateToProps)(MyComp)
pattern possible (but a pain to do and maintain) but I believe a better thing to do would be to look into converting this connect
function to Haxe semantics. eg. I believe a macro could effectively replace it.
from haxe-react.
I successfully use react-redux's connect()
with the following code
class VisibleTodoList {
static function mapStateToProps(state) {
return {...}
}
static function mapDispatchToProps(dispatch) {
return {...}
}
static function __init__()
// kind of hack to assign something to a class, but works
untyped VisibleTodoList = js.Lib.require('react-redux').connect(mapStateToProps, mapDispatchToProps)(TodoList);
}
class TodoList extends ReactComponent {
override function render() {
return jsx('...');
}
}
from haxe-react.
This is starting to be clever, but that isn't really a scalable pattern of you want to heavily use HOCs.
from haxe-react.
What are the possible issues with this approach, seems to be fine if the end user is given the choice to either use the lower order component vs the higher order one in a Render.
from haxe-react.
Any updates on haxe-react
HOC patterns? HOCs are not uncommon in a React codebase so having some utility or clear pattern to straightforwardly apply HOCs from within haxe-react
would be nice. For now, the best examples of what @kevinresol has shown above.
from haxe-react.
Current recommended approach would be using @:jsxStatic
:
@:jsxStatic(wrapped)
class VisibleTodoList {
static function mapStateToProps(state) {
return {...}
}
static function mapDispatchToProps(dispatch) {
return {...}
}
static final wrapped = js.Lib.require('react-redux').connect(TodoList, mapStateToProps, mapDispatchToProps);
}
PS: it's better BTW to declare mapDispatchToProps
as a static object.
from haxe-react.
There are with react-next https://github.com/kLabz/haxe-react/blob/next/doc/wrapping-with-hoc.md
Should be (mostly?) applicable to this lib as well, actually (see #102)
from haxe-react.
Oh actually @wrap
. Undocumented so might as well not exist :D
from haxe-react.
Copying everything from the link above up to @:publicProps(TProps)
part should cover basic usage for haxe-react.
from haxe-react.
Reorganised and completed the documentation about it - check the readme :)
from haxe-react.
Nice, readme looks a lot better like that 👍
from haxe-react.
Related Issues (20)
- some like macro-components? HOT 1
- Remove Dynamic context field from ReactComponent HOT 4
- Macro - replaceEntities Unicode Issue
- [job] Haxe React Freelancers wanted
- readme.md refers to incorrect imports
- Unexpected use of 'self' no-restricted-globals HOT 5
- Loading a JS module from Haxe in the same project HOT 4
- Invalid escape sequence \u. UTF-16 surrogates are not allowed in strings HOT 4
- Inconsistent defaultProps behavior in debug / no debug mode HOT 8
- PureComponent: invalid number of type parameters HOT 2
- Cannot read property 'value' of undefined HOT 1
- is jsx not support array tag? HOT 3
- Using external jsx instead of inline one HOT 2
- No changes concerning react 16 in the haxelib library version HOT 3
- Functional components is shown as <Unknow>...</Unknow> in chrome dev tools HOT 10
- Fragment support react v16.2 HOT 4
- Wrong 'ReactDOM.createPortal' method annotation
- setState callback typing issue HOT 1
- Inline mode issue? HOT 6
- The lib doesn't work with haxe 4 preview HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from haxe-react.