React報錯之Cannot assign to ‘current’ because it is a read-only property

  • 2022 年 8 月 11 日
  • 筆記

正文從這開始~

總覽

當我們用一個null值初始化一個ref,但在其類型中不包括null時,就會發生”Cannot assign to ‘current’ because it is a read-only property”錯誤。為了解決該錯誤,請在ref的類型中包含null。比如說,const ref = useRef<string | null>(null)

react-cannot-assign-to-current-because-read-only.png

這裡有個例子來展示錯誤是如何發生的。

// App.tsx
import {useEffect, useRef} from 'react';

const App = () => {
  const ref = useRef<string>(null);

  useEffect(() => {
    // ⛔️ Error: Cannot assign to 'current' because it is a read-only property.ts(2540)
    ref.current = 'hello';
  }, []);

  return (
    <div>
      <h2>hello world</h2>
    </div>
  );
};

export default App;

上面例子的問題在於,當我們將null作為初始值傳遞到useRef鉤子中時,並且我們傳遞給鉤子的泛型中沒有包括null類型,我們創建了一個不可變的ref對象。

正確的泛型

為了解決該錯誤,我們必須在傳遞給鉤子的泛型中包括null類型。

// App.tsx
import {useEffect, useRef} from 'react';

const App = () => {
  // 👇️ include null in the ref's type
  const ref = useRef<string | null>(null);

  useEffect(() => {
    ref.current = 'hello';
  }, []);

  return (
    <div>
      <h2>hello world</h2>
    </div>
  );
};

export default App;

ref的類型中,我們使用聯合類型來包括null類型,這使它成為可變ref對象。

現在這個例子中ref的類型是字元串或null,它的current屬性可以賦值為這兩種類型中的任意一種的值。

DOM元素

如果你的引用指向一個DOM元素,情況也是一樣的。如果你需要改變refcurrent屬性的值,你必須將鉤子的類型定為 const ref = useRef<HTMLElement | null>(null)

注意,如果你不直接賦值給它的current屬性,你不必在 ref 的類型中包含 null

// App.tsx
import {useEffect, useRef} from 'react';

const App = () => {
  const ref = useRef<HTMLInputElement>(null);

  useEffect(() => {
    ref.current?.focus();
  }, []);

  return (
    <div>
      <input ref={ref} type="text" defaultValue="" />
    </div>
  );
};

export default App;

上述例子中的ref是用來聚焦input元素的。因為沒有對其.current屬性進行賦值,所以沒有必要在其類型中包含null