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

4

63

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!

Ine answered 6/10, 2022 at 1:35 Comment(0)
G
70

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);
Galateah answered 6/10, 2022 at 1:39 Comment(0)
F
32

There are two types of ref : mutable or inmmutable

React.RefObject
React.MutableRefObject

your syntax 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 syntax as the other answers says. You must use parenthesis 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

Felty answered 27/10, 2023 at 14:6 Comment(0)
F
9

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.

Filia answered 6/10, 2022 at 1:40 Comment(0)
E
2

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.

Ensign answered 6/10, 2022 at 1:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.