1

I'm building a React website with fluentui/react-nothstar package controls. Below you can find a simplified example of Text + Button. My scenario is to access the text control when the button is pressed. I need something like document.findElementById which works via refs in React. It works great for component controls (that extends React.Component) but fails for Northstar components with the error:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

Based on the warning details and the Text control definition, it looks like it's a function component and I have to use React forwardRef to access its properties. I tried multiple ways to do this here, here, and here but wasn't successful.

import React from 'react';
import {
    Text,
    Button,
}
    from '@fluentui/react-northstar';

class Welcome extends React.Component {

    private textRef: any = React.createRef();

    private doJob1() {
        console.log("doJob1 executed");
        console.log(this.textRef.current); // returns null
    }

    render() {
        return (
            <div>
                <div>Welcome</div>
                <div>
                    <Text
                        ref={this.textRef}
                        content="My fancy text control" />
                    <Button
                        onClick={this.doJob1.bind(this)}
                        content="My fancy button" />

                </div>
            </div>
        );
    }
}

export default Welcome;

In most cases, I can avoid direct element access by use props and state but in some cases, I still need a component reference (change focus, open dialog, update values not defined in my state).

What is the right way to access the Text control in the Button click handler in the example above?

Mando
  • 11,414
  • 17
  • 86
  • 167

2 Answers2

1

In that case, the library needs to forward the ref, which apparently they don't.

But in general, you want to use controlled components to capture user input like that. Basically, you need to set a variable to track the value in the parent component (Welcome, in your case), pass it down as the value to the <Text /> component and capture the changes from its onChange. Then, on the button's onClick, the value will be up to date with whatever is the user input.

  • Thanks! That is exactly what I use for maintaining a single source of truth and it works fine in most cases but not all. For example, Datepicker `onDateChange` doesn't supply the new value in event.target.value and I need the control reference to read the value: https://github.com/microsoft/fluentui/issues/18458 – Mando Jun 08 '21 at 07:07
  • I don't know the specifics about the fluent ui, but have you tried onDateChange={console.log}, to see what's the format it sends back? – Gabriel Vilches Alves Jun 09 '21 at 08:57
  • If I print tp console `event.target`, instead of the control, it gives me the datePicker button `` and I cannot fetch the value via the usual `event.target.value`. – Mando Jun 22 '21 at 03:49
1

Turned out that Ref was designed for that:

<Ref innerRef={this.textRef}>
    <Text content="My fancy text control" />
</Ref>
Mando
  • 11,414
  • 17
  • 86
  • 167