乐趣区

关于react.js:React报错之Object-is-possibly-null

注释从这开始~

类型守卫

应用类型守卫来解决 React 中 useRef 钩子“Object is possibly null”的谬误。比如说,if (inputRef.current) {}。一旦 null 被排除在 ref 的类型之外,咱们就可能拜访 ref 上的属性。

上面是一个谬误如何产生的示例。

import {useEffect, useRef} from 'react';

export default function App() {const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {// ⛔️ Object is possibly 'null'.ts(2531)
    inputRef.current.focus();}, []);

  return (
    <div>
      <input ref={inputRef} type="text" id="message" />
      <button>Click</button>
    </div>
  );
}

代码片段中的问题是,TypeScript 不能确保咱们将一个元素或者一个值赋值给 ref,所以它的 current 属性可能为null

为了解决这个谬误,在拜访 ref 类型上的属性之前,咱们必须应用类型守卫来从其类型中排除null

import {useEffect, useRef} from 'react';

export default function App() {const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {
    // 👉️ ref could be null here
    if (inputRef.current != null) {
      // 👉️ TypeScript knows that ref is not null here
      inputRef.current.focus();}
  }, []);

  return (
    <div>
      <input ref={inputRef} type="text" id="message" />
      <button>Click</button>
    </div>
  );
}

咱们应用简略的 if 语句作为类型守卫,来确保 ref 上的 current 属性不存储 null。当程序进入到if 代码块中,TypeScript 就会晓得 ref 对象上的 current 属性就不会存储null

确保在 useRef 钩子上应用泛型,正确的类型申明 ref 上的 current 属性。

留神,咱们传递了一个泛型来将 ref 的值类型申明为HTMLInputElement

一些罕用的类型有:HTMLInputElementHTMLButtonElementHTMLAnchorElementHTMLImageElementHTMLTextAreaElementHTMLSelectElement 等等。

如果你在 ref 中存储了不同的值,请确保将特定类型传递给 useRef 钩子的泛型,例如const ref = useRef<{name: string}>(null);

如果 ref 上的 current 属性存储了null,咱们也能够应用可选链?. 操作符进行短路运算。

import {useEffect, useRef} from 'react';

export default function App() {const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {// 👇️ optional chaining (?.)
    inputRef.current?.focus();}, []);

  return (
    <div>
      <input ref={inputRef} type="text" id="message" />
      {/* Cannot find name 'button'.ts(2304) */}
      <button>Click</button>
    </div>
  );
}

如果援用是空值(null或者 undefined),可选链?. 操作符会进行短路运算,而不会抛出谬误。换句话说,如果ref 上的 current 属性存储了 null,操作符会短路运算从而返回undefined。而不会在undefined 上尝试调用 focus 办法,导致一个运行时谬误。

非空断言

另一种解决方案是应用非空断言 ! 操作符。

import {useEffect, useRef} from 'react';

export default function App() {const inputRef = useRef<HTMLInputElement>(null);

  useEffect(() => {// 👇️ using non-null (!) assertion
    inputRef.current!.focus();}, []);

  return (
    <div>
      <input ref={inputRef} type="text" id="message" />
      {/* Cannot find name 'button'.ts(2304) */}
      <button>Click</button>
    </div>
  );
}

在 TypeScript 中,感叹号标记被称为非空断言操作符。被用来从类型中移除 nullundefined,而不必进行任何显式的类型查看。

当咱们应用非空断言时,基本上咱们就是在通知 TS,ref对象上的 current 属性不会存储 null 或者undefined

请留神,这种办法不是类型平安的,因为 TypeScript 不执行任何查看以确保属性不是空的。

总结

造成 “Object is possibly null” 的谬误是因为 useRef() 钩子能够传递一个初始值作为参数,而咱们传递 null 作为初始值。该钩子返回一个可变的 ref 对象,其 .current 属性被初始化为所传递的参数。

当传递 ref prop 给一个元素时,比方 <input ref={myRef} />,React 将ref 对象的 .current 属性设置为相应的 DOM 节点,但 TypeScript 无奈确定咱们是否会将 ref 设置为 DOM 元素,或在咱们的代码中稍后设置其值。

退出移动版