Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use refs in React with Typescript

People also ask

How do you use REF in functional component TypeScript?

To use refs with functional components use a special useRef hook. It is a generic function, so we can pass a type-parameter, that will tell TypeScript what type is acceptable for this ref. // using `HTMLInputElement` as a type parameter. // to bind the element with the ref.

How do you type refs in React?

You can create a ref by calling React. createRef() and attaching a React element to it using the ref attribute on the element. We can “refer” to the node of the ref created in the render method with access to the current attribute of the ref. From the example above, that would be this.

How do I use a useRef hook in TypeScript?

To use useRef with TypeScript, it is actually pretty easy, all you need to do is provide the type that you want to the function via open and closed chevrons like you would with other React hooks like so: const myRef = useRef<number>(0) .


If you’re using React 16.3+, the suggested way to create refs is using React.createRef().

class TestApp extends React.Component<AppProps, AppState> {
    private stepInput: React.RefObject<HTMLInputElement>;
    constructor(props) {
        super(props);
        this.stepInput = React.createRef();
    }
    render() {
        return <input type="text" ref={this.stepInput} />;
    }
}

When the component mounts, the ref attribute’s current property will be assigned to the referenced component/DOM element and assigned back to null when it unmounts. So, for example, you can access it using this.stepInput.current.

For more on RefObject, see @apieceofbart's answer or the PR createRef() was added in.


If you’re using an earlier version of React (<16.3) or need more fine-grained control over when refs are set and unset, you can use “callback refs”.

class TestApp extends React.Component<AppProps, AppState> {
    private stepInput: HTMLInputElement;
    constructor(props) {
        super(props);
        this.stepInput = null;
        this.setStepInputRef = element => {
            this.stepInput = element;
        };
    }
    render() {
        return <input type="text" ref={this.setStepInputRef} />
    }
}

When the component mounts, React will call the ref callback with the DOM element, and will call it with null when it unmounts. So, for example, you can access it simply using this.stepInput.

By defining the ref callback as a bound method on the class as opposed to an inline function (as in a previous version of this answer), you can avoid the callback getting called twice during updates.


There used to be an API where the ref attribute was a string (see Akshar Patel's answer), but due to some issues, string refs are strongly discouraged and will eventually be removed.


Edited May 22, 2018 to add the new way of doing refs in React 16.3. Thanks @apieceofbart for pointing out that there was a new way.


React.createRef (class comp.)

class ClassApp extends React.Component {
  inputRef = React.createRef<HTMLInputElement>();
  
  render() {
    return <input type="text" ref={this.inputRef} />
  }
}

React.useRef (Hooks / function comp.)

a) Use readonly refs for React-managed DOM nodes:
const FunctionApp = () => {
  // note the passed-in `null` arg ----------------v
  const inputRef = React.useRef<HTMLInputElement>(null)
  return <input type="text" ref={inputRef} />
}

inputRef.current becomes a readonly property by initializing its value with null.

b) Use mutable refs for arbitrary stored values akin to instance variables:
const FunctionApp = () => {
  const renderCountRef = useRef(0)
  useEffect(() => {
    renderCountRef.current += 1
  })
  // ... other render code
}

Note: Don't initialize useRef with null in this case - it would make the renderCountRef type readonly (see example). If you need to provide null as initial value, do this:

const renderCountRef = useRef<number | null>(null)

Callback refs (both)

// Function component example, class analogue 
const FunctionApp = () => {
  const handleDomNodeChange = (domNode: HTMLInputElement | null) => {
    // ... do something with changed dom node.
  }
  return <input type="text" ref={handleDomNodeChange} />
}

Note: String Refs are considered legacy and omitted for the scope of this answer.

Playground sample


One way (which I've been doing) is to setup manually :

refs: {
    [string: string]: any;
    stepInput:any;
}

then you can even wrap this up in a nicer getter function (e.g. here):

stepInput = (): HTMLInputElement => ReactDOM.findDOMNode(this.refs.stepInput);

Since React 16.3 the way to add refs is to use React.createRef as Jeff Bowen pointed in his answer. However you can take advantage of Typescript to better type your ref.

In your example you're using ref on input element. So they way I would do it is:

class SomeComponent extends React.Component<IProps, IState> {
    private inputRef: React.RefObject<HTMLInputElement>;
    constructor() {
        ...
        this.inputRef = React.createRef();
    }

    ...

    render() {
        <input type="text" ref={this.inputRef} />;
    }
}

By doing this when you want to make use of that ref you have access to all input methods:

someMethod() {
    this.inputRef.current.focus(); // 'current' is input node, autocompletion, yay!
}

You can use it on custom components as well:

private componentRef: React.RefObject<React.Component<IProps>>;

and then have, for example, access to props :

this.componentRef.current.props; // 'props' satisfy IProps interface

If you're using React.FC, add the HTMLDivElement interface:

const myRef = React.useRef<HTMLDivElement>(null);

And use it like the following:

return <div ref={myRef} />;

EDIT: This is no longer the right way to use refs with Typescript. Look at Jeff Bowen's answer and upvote it to increase its visibility.

Found the answer to the problem. Use refs as below inside the class.

refs: {
    [key: string]: (Element);
    stepInput: (HTMLInputElement);
}

Thanks @basarat for pointing in the right direction.