Skip to content

refs #100

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 11, 2017
Merged

refs #100

merged 8 commits into from
Oct 11, 2017

Conversation

coot
Copy link

@coot coot commented Jun 27, 2017

  • React.DOM.Props.ref - set ref property (string)
  • React.readRef - read ref through Foreign

String refs are not yet deprecated, but they might be at some point and React-15.6.1 docs do not event mention them. Nevertheless we should support them.

I'd be keen to change readRef type to

readRefs :: String -> Foreign -> Eff (refs :: ReactRef (read :: Read | access) | eff) (Either MultipleErrors Node)

i.e.

  • run runExcept
  • use Foreign directly

This way it will be also use able if one sets a ref using a callback. Then on could pass toForeigh this and get back the ref. Setting callback refs is not included in the patch but I'd be happy to find a solution for that - maybe with a more fresh mind in the morning :)

Marcin Szamotulski added 3 commits June 28, 2017 00:10
* React.DOM.Props.ref - set ref property (string)
* React.readRef - read ref through Foreign
@coot coot changed the title [WIP] refs refs Jun 28, 2017
@paf31
Copy link
Contributor

paf31 commented Jul 1, 2017

I think this means adding a dependency on foreign which comes with a lot of dependencies, whereas react right now has almost none. I'd prefer to avoid the dependency if possible.

@coot
Copy link
Author

coot commented Jul 8, 2017

The other option is to use Refs instead of Foriegn and to provide safe way of writing a ref to Refs and reading it from there (as a Maybe). Then we could also support callback arguments for the ref property which would write to Refs.

@coot
Copy link
Author

coot commented Jul 8, 2017

  • now it only introduces purescript-dom dependency, which anyway will be in any project
  • I think we could be less conservative and use HTMLElement instead of Node type. Storing an attribute node (which is a Node but not Element), is possible but not something usable.
  • we could be more conservative on effects that we allow in refCb, for example (refs :: ReactRef (write :: Write | access), state :: ReactState () | eff)

@ethul
Copy link
Contributor

ethul commented Jul 8, 2017 via email

@coot
Copy link
Author

coot commented Jul 8, 2017

purescript-nullable is using == null to check if something is null or not and undefined == null returns true. TherefCb is called with null (when a component unmounts), so it might be set to null. Undefinable is using === undefined so this will not detect a null. So Nullable looks safer to me.

@ethul
Copy link
Contributor

ethul commented Jul 8, 2017 via email

@paf31
Copy link
Contributor

paf31 commented Jul 8, 2017

Unfortunately, dom still pulls in quite a few dependencies. I'd really like to avoid adding more dependencies here if we can - I really like that all you need is prelude and eff.

I'll have a think about some options.

@coot
Copy link
Author

coot commented Jul 9, 2017

We could make refs polymorphic in the type. That would leave choice weather use Foreign or HTMLElement or a some more specific type like HTMLInputElement (Foreign seems the safest and most generic type though.)

Since this library is oriented towards the web, a requirement of purescript-dom or even purescript-foreign looks really minimal to me; purescript-react-dom already requires purescript-dom (and thus purescript-foreign).

@ethul
Copy link
Contributor

ethul commented Jul 9, 2017

After thinking about this further. I agree with @paf31. I think if we can avoid depending on purescript-dom, it would be ideal. For example, I don't think we'd necessarily need purescript-dom in a react native app.

-- | ```
refCb
:: forall access eff
. (Node -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick note, would it make sense for this to be Nullable Node?
https://facebook.github.io/react/docs/refs-and-the-dom.html#caveats

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick note: I am wondering if perhaps refCb should be called ref since it is the encourage usage in React. Maybe the current ref prop can be called refString or something along those lines. What do you think?

@ethul
Copy link
Contributor

ethul commented Aug 29, 2017

I think it would be very useful to merge in this PR. However, I do think it would be best to avoid the DOM dependency. Would it make sense to replace Node with just a ref? E.g.,

ref :: forall access eff ref. (Nullable ref -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)

@paf31
Copy link
Contributor

paf31 commented Sep 2, 2017

But wouldn't the user be able to use such a function unsafely?

Do we even use the ref type anywhere? What about just creating a new foreign data type, and then the user can coerce it if they want to pull in dom.

@ethul
Copy link
Contributor

ethul commented Sep 2, 2017 via email

Still adds two small dependencies
* purescript-maybe
* purescript-nullable
src/React.purs Outdated
@@ -294,6 +300,26 @@ foreign import getRefs :: forall props state access eff.
ReactThis props state ->
Eff (refs :: ReactRefs (read :: Read | access) | eff) Refs

foreign import data Ref :: Type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add a comment here?

-- | ``` purescrript
-- | div [ refCb (writeRef this "inputEl") ] [...]
-- | ```
refCb
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this name so much, what about something like withRef?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually I don't like it either, withRef sounds much better :)

src/React.purs Outdated
String ->
Eff (refs :: ReactRefs (read :: Read | access) | eff) (Nullable Ref)

readRef :: forall props state access eff.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add comments to these as well?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ref type should also be documented, and advising the user to use unsafeCoerce make me feel I am doing something wrong, so either we provide a third library with Node -> Ref and Ref -> Node safe functions (purescript-react-refs) or we can include that in purescript-react-dom, which already depends on purescript-dom.
There are pros and cons of both, but either will provide a safe way for the basic operation.

By the way: using zypher & webpack (with uglify plugin) on purescript-isomorphic-react-example, which is pulling DOM for very basic stuff (access to location, history, search the mounting point in the DOM), pulls ~2.3KB of data from purescript-dom, which is ~0.5% of whole bundle (~400KB, which gzips to 94KB). zypher, to some extend can remove things from foreign modules that's why the overall code from DOM that lands in the bundle is pretty minimal.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion, I think purescript-react-dom would be a nice spot for functions that convert between Ref and Node. Similarly, in a purescript-react-native library, there could be functions that convert between Ref and something native.

-- | ```
refCb
:: forall access eff
. (Node -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a quick note: I am wondering if perhaps refCb should be called ref since it is the encourage usage in React. Maybe the current ref prop can be called refString or something along those lines. What do you think?

-- | ```
refCb
:: forall access eff
. (Ref -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a note, I think this may need to be

(Nullable Ref -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From react docs:

React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts.

And this is done to avoid memory leaks (DOM references used to leak in old IEs). If we write the ref only if it's not null, you'll prevent the original mechanism to prevent memory leaks.

So if we change this type signature (which I do like, since things are explicitly typed then) then we also need to change writeRef :: forall p s. ReactThis p s -> String -> Nullable Ref -> Eff ...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. I think it makes sense to write a Nullable Ref.

@coot
Copy link
Author

coot commented Sep 30, 2017

I added comments and renamed the function withRefs. Another PR will go topurescritp-react-dom which adds refToNode which is mentioned in the comments.

coot pushed a commit to coot/purescript-react-dom that referenced this pull request Sep 30, 2017
-- | ```
withRef
:: forall access eff
. (Ref -> Eff (refs :: ReactRefs (write :: Write | access) | eff) Unit)
Copy link
Contributor

@ethul ethul Sep 30, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Quick question: Did we want this to be Nullable Ref? Or are we thinking that the possibility the ref is null would be handled elsewhere.
https://facebook.github.io/react/docs/refs-and-the-dom.html#caveats

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. Having here Nullable Ref will be more explicit, so I prefer this. Then in the React.DOM.refToNode we will not need to use unsafeCoerce

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will only need to add a comment, that if one is attaching the ref to ReactThis one should do that using the Nullable Ref rather than Ref itself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great! Thanks!

ref = unsafeMkProps "ref"

-- | You can use `writeRef` to store a reference on `Refs`.
-- | ``` purescrript
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quick note: should be purescript

@ethul
Copy link
Contributor

ethul commented Oct 4, 2017

Looking great! @paf31 Do you have any other comments for this one?

@ethul ethul merged commit 03d52a5 into purescript-contrib:master Oct 11, 2017
ethul pushed a commit to purescript-contrib/purescript-react-dom that referenced this pull request Oct 11, 2017
@coot coot deleted the refs branch October 12, 2017 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants