andreaferretti / react.nim

React.js bindings for Nim
Apache License 2.0
91 stars 6 forks source link

React Hooks? #5

Open kristianmandrup opened 4 years ago

kristianmandrup commented 4 years ago

Any binding for React hooks? How would you best support this kind of functionality in Nim? For state management, I think dispatching Custom DOM Events is sufficient (see this approach with Micro Frontends in single-spa) perhaps combined with a light weight state management lib.

Would be awesome with bindings for RxJS for more complex apps.

andreaferretti commented 4 years ago

Any binding for React hooks?

I don't use React hooks. It seems to me a kludgy and convoluted way to support state in components that are implemented as functions, and so should be stateless. At the beginning React had a simple and clear model that could be learned in 30 minutes and would scale to very complex apps. I do not understand at all why they are moving in this direction.

How would you best support this kind of functionality in Nim?

I am not sure, as I do not use hooks. If you do find a way to create bindings for such functionality in Nim, though, I would be happy to accept a PR, but I am not interested in implementing it myself.

For state management, I think dispatching Custom DOM Events is sufficient (see this approach with Micro Frontends in single-spa) perhaps combined with a light weight state management lib.

I use to manage state by passing functions that react to events in the props of react components. Other people may be interested in a lightweight state mangament lib, but this is another project entirely. These are bindings for React.

Would be awesome with bindings for RxJS for more complex apps.

I like the Rx approach, and I think that bindings to RxJS or a reactive framework in Nim would be nice, but, again, it would be another project

kristianmandrup commented 4 years ago

I agree with all your points. I like something like MeiosisJS for a very lightweight, flexible approach. Would love to work on bindings for RxJS. You have any good resources for how to write JS FFI bindings? Perhaps you could write a blog post on it sometime or add it to the official docs, using some of the react bindings as an example.

I'd live if you could get me started... I have the Nim in Action book that I read a while back. Time to get back to Nim now that it has reached 1.0.

Cheers!

andreaferretti commented 4 years ago

You have any good resources for how to write JS FFI bindings?

No, but the development of this library is what made me start the work on jsffi

Perhaps you could write a blog post on it sometime or add it to the official docs, using some of the react bindings as an example.

Agreed, I think the official tutorials could be enriched with one dedicated to interoperating with Javascript. I will see if I find the time to draft something, but unfortunately I do not have much time these days :-)

kristianmandrup commented 4 years ago

jsffi looks amazing :) However even the small jQuery example at the top is hard to understand for an ffi and Nim noob like me. Would love to see some more simple examples that explains what is going on for each line. Like what are the .importc and .nodecl doing when declaring the vars? A hello world sample bindings repo using jsffi would be great, with a decent Readme or comments to explain how it works :)

I'd love to write a blog post on it with some support if you have the time

Thanks for your help and responses :)

andreaferretti commented 4 years ago

Like what are the .importc and .nodecl doing when declaring the vars?

This is explained in the manual

The noDecl pragma can be applied to almost any symbol (variable, proc, type, etc.) and is sometimes useful for interoperability with C: It tells Nim that it should not generate a declaration for the symbol in the C code.

In short, var document {.importc, nodecl.}: JsObject says that document is a native variable, and that Nim should not emit a var document statement in the generated JS. The variable is declared in Nim, so that subsequent code can use it, Nim can reason on its type and correct scope rules are applied, but then there is no line declaring the same variable in javascript - Nim will just expect that the document variable somehow exists, which is correct since it is a global in JS

kristianmandrup commented 4 years ago

Thanks. That helps. Was also wondering about the use of the importcpp pragma.

I guess they (nim core team) should ideally rename it to a more generic name (or alias) since it is not only for C++ as the import/pragma target.

So proc jq(selector: JsObject): JsObject {.importcpp: "$(#)".} creates a jq nim procedure (aka function) that takes an object and returns an object. Under the hood it calls $(#) where the # is the selector Object argument in the nim procedure declaration. The rest of the example is pretty basic. Starting to get the gist of ffi. Thanks again :)

kristianmandrup commented 4 years ago

I started a new repo react-16.nim where I'm trying to add bindings for React 16 including hooks.

Currently having some issues, such as with createClass (now deprecated, in a global function, in a separate npm library). Wondering if you could spare a few minutes to have a look.

kristianmandrup commented 4 years ago

I think my main issue is a lack of understanding of the syntax of RootObj

type
  Context*{.importc.} = ref object of RootObj
  Consumer*{.importc.} = ref object of RootObj
  Producer*{.importc.} = ref object of RootObj
  ReactGlobal*{.importc.} = ref object of RootObj
    version*: cstring
  ReactDOMGlobal*{.importc.} = ref object of RootObj
    version*: cstring
  ReactDescriptor*[P, S] {.importcpp.} = ref object of RootObj

Trying to make createReactClass a global (top level) function, not a method on React

proc createReactClass*(c: ReactDescriptor): ReactComponent

# to enable concurrent mode (Suspense) on VDOM
proc createRoot*(rootElement: Element): ReactNode
{.pop.}
andreaferretti commented 4 years ago

I started a new repo react-16.nim

Great to hear that! :-)

Currently having some issues, such as with createClass

Latest version of React encourage to use native ES6 classes instead of defining them with createClass, that's the reason for the deprecation. There is this post where the implementation of classes is discussed, I don't know if it can be of some help. The issue, of course, is that Nim itself does not have classes, and thus the javascript backend does not have a straightforward way to emit code that uses them.

I think my main issue is a lack of understanding of the syntax of RootObj

The annotation of RootObj is necessary when compiling to C/C++ if you want to do dymamic dispatch. In this case, the compiler has to emit some tags that allow to do runtime casting. I don't think it is strictly necessary on JS, since the javascript backend will take care of the dispatch of its own, but it can't hurt.

Trying to make createReactClass a global (top level) function, not a method on React

For that to work, you have to {.importc.} the function, since you assume that it is available and you just want to use it

proc createReactClass*(c: ReactDescriptor): ReactComponent {.importc.}
andreaferretti commented 4 years ago

By the way, since your library is a fork of this one, it would be good courtesy to mention this in the README.