How to use React useRef with TypeScript
Tags: react, abotwrotethis
Published: 2023-04-09 17:02:02

If you're a developer using React and TypeScript, you'll need to know how to use `useRef` to reference elements in your application. In this tutorial, we will explore how to use `useRef` along with TypeScript to leverage the strengths of both technologies.

## What is useRef?

`useRef` is a React hook that provides a way to reference an element in your application, similar to the way you would with the `getElementById` function in vanilla JavaScript. However, `useRef` is more powerful because it can be used to reference any React component, not just DOM elements.

With `useRef`, you can preserve a value between renders without causing a re-render. This is useful for working with mutable values that don’t affect the render outcome or that would require non-reactive workarounds. By default, `useRef` returns a mutable object with a `current` property that points to the current value.

## Using `useRef` with TypeScript

When using `useRef` with TypeScript, there are a few things to keep in mind. First, TypeScript requires that you specify the type of the value being referenced. Second, you need to specify the type of the component being referenced. Finally, you will likely want to specify the type of the `useRef` itself.

Here is an example of using `useRef` with TypeScript:

```tsx
import React, { useRef } from 'react';

type Props = {
  text: string;
};

const MyComponent: React.FC<Props> = ({ text }) => {
  const inputEl = useRef<HTMLInputElement>(null);

  return (
    <div>
      <input type="text" ref={inputEl} />
      <p>The input value is: {inputEl.current?.value}</p>
      <p>The prop value is: {text}</p>
    </div>
  );
};

export default MyComponent;
```

In this example, we defined a props type that includes a text property. The `MyComponent` component uses `useRef` to reference the input element using the HTMLInputElement type. The input reference is then used to display the input's value.

Note that we used the `?` operator to access the `value` property. This is because the `current` property of `useRef` is initially `null`. The `?` operator protects against null/undefined errors.

## An Advanced Example

Now, let's take a look at a more advanced example that demonstrates dispatching an action with `useRef` and TypeScript. We will use Redux and implement a very basic counter.

First, we will create a Redux store with `createSlice` and `configureStore`:

```tsx
import { createSlice, configureStore } from '@reduxjs/toolkit';
import { useDispatch } from 'react-redux';
import { useCallback, useMemo } from 'react';
import { TypedUseSelectorHook, useDispatch as useReduxDispatch, useSelector as useReduxSelector } from 'react-redux';
import { RootState } from './store';

type CounterState = {
  value: number;
};

const initialState: CounterState = {
  value: 0,
};

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment(state) {
      state.value += 1;
    },
    decrement(state) {
      state.value -= 1;
    },
  },
});

export const { increment, decrement } = counterSlice.actions;

export const store = configureStore({
  reducer: {
    counter: counterSlice.reducer,
  },
});
```

Next, we implement a counter component that renders a button and displays the current count:

```tsx
import React, { useRef } from 'react';
import { useSelector } from 'react-redux';
import { RootState } from '../store';
import { increment } from '../store/counter';

const Counter = () => {
  const count = useSelector<RootState>((state) => state.counter.value);
  const dispatch = useDispatch();

  const buttonRef = useRef<HTMLButtonElement>(null);

  const handleIncrement = useCallback(() => {
    if (buttonRef.current) {
        buttonRef.current.blur();
    }
    dispatch(increment());
  }, [dispatch]);

  return (
    <div>
      <p>Count: {count}</p>
      <button type="button" onClick={handleIncrement} ref={buttonRef}>
        Increment
      </button>
    </div>
  );
};

export default Counter;
```

In this example, we use `useSelector` to select the current count from the Redux store. We then define a `handleIncrement` function that uses `useRef` to reference the button element and update the count with `dispatch`. The `useCallback` hook ensures that the reference to the button element is not recreated on every render.

## Conclusion

By now, you should have a good understanding of how to use `useRef` and TypeScript in your React applications. Remember, `useRef` allows you to reference elements and values without causing a re-render, which is useful for mutable values that don't affect the render outcome.

If you're looking to take your React and TypeScript skills to the next level, consider exploring other hooks and technologies such as Redux, React Router, and GraphQL. These technologies work seamlessly with React and TypeScript and make it even easier to build complex applications.