Cannot assign to 'current' because it is a read-only property

33.7k Views Asked by At

I am trying to have a useRef obj to be either null or a function here is code snippet

import "./styles.css";
import { useState, useRef, useEffect } from "react";
export default function App() {
  const testRef = useRef<string | null>(null);
  const unblockRef = useRef<() => void | null>(null);

  useEffect(() => {
    const test = () => {
      console.log("hey");
    };

    testRef.current = "";

    // this would give the error code
    unblockRef.current = null;
    // unblockRef.current = "saddsa";
  }, []);
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
    </div>
  );
}

here is playground link, from other stack overflow post, it seems like i just need to pass null type when we initialize the useRef obj.

I test the logic with testRef, which works fine, it seems like if the useRef type is function that would give trouble, Thanks for any kinds of help!

4

There are 4 best solutions below

0
technophyle On BEST ANSWER

It's simply a TypeScript error. Your syntax is problematic:

const unblockRef = useRef<() => void | null>(null);

This is interpreted as a function that returns either void or null.

So, you need to make sure it's a function or null:

const unblockRef = useRef<(() => void) | null>(null);
0
GROVER. On

When assigning multiple types to a variable, if one of those types is a callback, you must wrap the callback in its own set of parenthesis.

const unblockRef = useRef<(() => void) | null>(null);

This is because you can return multiple types from a function. So, logically, TypeScript thinks your function will return either void or null - as opposed to just void.

0
romellem On

Your problem is how you are using the | operator. Namely, the precedence for this type:

() => void | null

is actually

() => (void | null)

If you add some explicit parens to make the type

const unblockRef = useRef<(() => void) | null>(null);

then you are able to reassign it.

0
Paolo Biavati On

There are two types of ref : mutable or inmutable

React.RefObject
React.MutableRefObject

your sintax for testRef works ( | null ) is the key...

  const testRef = useRef<string | null>(null);

this way you implicit create a React.MutableRefObject and can assign

testRef.current = "some string";

in the other case unblockRef is only React.RefObject due to incorrect sintax as the other answers says. You must use parentesis due to operators precedence.

const unblockRef = useRef<(() => void) | null>(null);

Anyway an explicit declaration could also be used:

const testRef:React.MutableRefObject<string | null> = useRef<string | null>(null);

const unblockRef:React.MutableRefObject<(() => void)| null> = useRef<(() => void) | null>(null);

here there is a very good explanation article