Skip to content
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

How to obtain a component ref in a function component? #240

Open
kentcb opened this issue Apr 13, 2023 · 5 comments
Open

How to obtain a component ref in a function component? #240

kentcb opened this issue Apr 13, 2023 · 5 comments

Comments

@kentcb
Copy link

kentcb commented Apr 13, 2023

Hi,

I'm basically trying to figure out the equivalent of the following JS(X):

import { useRef } from 'react';

function MyComponent() {
  const componentRef = useRef(null);

  // Function to handle a button click
  function handleClick() {
    // Access the component using the ref object
    console.log(componentRef.current);
  }

  return (
    <div ref={componentRef}>
      <button onClick={handleClick}>Click me</button>
    </div>
  );
}

That is, I need to obtain a reference to the ReactElement representing the component itself. Note that I am making an assumption that the above JS is actually correct and that componentRef is a reference to the component itself - I haven't actually verified this.

If I do the obvious thing:

FunctionComponent.Of<Props>(
        (fun props ->
            let rootHook = Hooks.useRef<Option<ReactElement>> = None

            let root = // create the root element, passing rootHook to things that need access to the component itself
				
            rootHook.current <- Some root
            root
        )

It doesn't work because I'm capturing a ReactElement rather than the component itself.

If I try to use a dom.div with Props.RefValue, it captures a browser element rather than a ReactElement (let alone the component).

So I'm unclear on how I obtain a reference to the component itself from within the implementation of a function component. In a class-based component, one would simply use this, but I can't use a class-based component.

Thanks

PS. In case you're wondering, my use case is I am trying to get a reference to the component to pass it to a ReactXP Popup as an anchor. The Popup needs to be anchored to the component that displays it.

@MangelMaxime
Copy link
Member

If I try to use a dom.div with Props.RefValue, it captures a browser element rather than a ReactElement (let alone the component).

This is normal, the ref you get is for the div element because the property is attached to the div. I don't remember seeing a ref returning a react component.

The equivalent of you JS code is:

// Dummy props to make the compiler happy
type Props =
    {|
        Count : int
    |}

let App =
    FunctionComponent.Of<Props>(fun props ->
        let ref = Hooks.useRef<Element option> None

        div [ RefValue ref]
            [
                button
                    [
                        OnClick (fun _ ->
                            JS.console.log ref.current
                        )
                    ] [ str "Click me" ]
            ]
    )

If you still need more help, we would need the JavaScript code that you are trying to reproduce.

@kentcb
Copy link
Author

kentcb commented Apr 13, 2023

I am unclear on what the equivalent JS is, but what I'm trying to replicate is being able to access this from within a class-based React component:

type private Props =
    {
        Title: string
    }

type SomeComponent(initialProps: Props) =
    inherit Fable.React.PureStatelessComponent<Props>(initialProps)

    let onPress (sourceReactComponentInstance: ReactElement) : unit =
        // Open a ReactXP Popup using sourceReactComponentInstance as the anchor

    override this.render() =
        button
            [
                // It's the "this" reference here that I am unable to find an equivalent for in a function-based component
                OnClick (fun _ -> onPress this)
            ]
            [ str this.props.Title ]

@MangelMaxime
Copy link
Member

Sorry, without an example of what is expected it is difficult to help you.

I tried to look at the documentation of ReactXP because I think this is what you use. But it seems like it doesn't use React but their own custom stuff. For example, they use Rx.Component and not ReactComponent, RX.Button and not button.

So I feel, like you need to create a binding for their library/ecosystem.

In React, the this that you try to access in your view is only about the state of the components not the reference of it in the DOM. If you want, the reference in the DOM you need to use Ref, or RefValue.

@kentcb
Copy link
Author

kentcb commented Apr 14, 2023

In React, the this that you try to access in your view is only about the state of the components not the reference of it in the DOM. If you want, the reference in the DOM you need to use Ref, or RefValue.

Whatever it is, it's what I need to get hold of from within a function component. Is that possible? This is not a ReactXP-specific question - I just happen to be using it. The point of the question is to understand how to do the equivalent of accessing the this pointer from the context of a function component.

@alfonsogarciacaro
Copy link
Member

Looking at an example from ReactXP code, the code is very similar to the one from @MangelMaxime above. See how the reference is captured and passed through getAnchor option.

So I would use the same code. If you have a problem with the types, you can use unbox for casting.

// Declare ref
let anchor = Hooks.useRef<Element option> None

// Capture ref
div [ RefValue anchor] ...

// Access ref
unbox anchor.current.Value

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants