2

React报错之Object is possibly null

 2 years ago
source link: https://www.fly63.com/article/detial/11964
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

更新日期: 2022-08-01阅读: 18标签: React分享

扫一扫分享

正文从这开始~

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

62e743282d7ca.jpg

下面是一个错误如何发生的示例。

import {useEffect, useRef} from 'react';

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

  useEffect(() => {
    // :no_entry:️ 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(() => {
    // :point_right:️ ref could be null here
    if (inputRef.current != null) {
      // :point_right:️ 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 。

一些常用的类型有: HTMLInputElement ,  HTMLButtonElement ,  HTMLAnchorElement ,  HTMLImageElement ,  HTMLTextAreaElement ,  HTMLSelectElement 等等。

如果你在 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(() => {
    // :point_down:️ 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(() => {
    // :point_down:️ 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中,感叹号标记被称为非空断言操作符。被用来从类型中移除 null 和 undefined ,而不用进行任何显式的类型检查。

当我们使用非空断言时,基本上我们就是在告诉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元素,或在我们的代码中稍后设置其值。

原文来自:https://bobbyhadz.com/blog/react-useref-object-is-possibly-null

链接: https://www.fly63.com/article/detial/11964


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK