React 中需要操作元素时,可通过 findDOMNode() 或通过 createRef() 创建对元素的引用来实现。前者官方不推荐,所以这里讨论后者及其与 TypeScript 结合时如何工作。

React 中的元素引用

正常的组件中,可通过创建对元素的引用来获取到某元素然后进行相应操作。比如元素加载后将焦点定位到输入框。

class App extends Component {constructor(props){super(props);this.inputRef = React.createRef();}componentDidMount(){this.inputRef.current.focus()}render() {return (<div className="App"><input type="text" ref={this.inputRef}/></div>);}
}

创建对元素的引用是通过 React.createRef() 方法完成的。使用的时候,通过其返回对象身上的 current 属性可访问到绑定引用的元素。

React 内部对引用的 current 赋值更新发生在 componentDidMountcomponentDidUpdate 生命周期之前,即存在使用的时候引用未初始化完成的情况,所以 current 不一定有值。好的做法是使用前先判空。

if(this.inputRef.current){this.inputRef.current.focus()
}

在上面的示例中,之所以不用判空是因为我们在 componentDidMount 生命周期中使用,此时元素已经加载到页面,所以可以放心使用。

组件中引用的传递

对于原生 DOM 元素可以像上面那样创建引用,但对于自己写的组件,则需要使用 forwardRef() 来实现。

假如你写了个按钮组件,想要实现像上面那样,让使用者可通过传递一个 ref 属性来获取到组件中原生的这个 <button> 元素以进行相应的操作。

button.jsx

const FancyInput = props => <input type="text" className="fancy-input" />;

添加 ref 支持后的按钮组件:

button.jsx

const FancyInput = React.forwardRef((props, ref) => {return <input type="text" ref={ref} className="fancy-input" />;
});

forwardRef 接收一个函数,函数的入参中第一个是组件的 props,第二个便是外部传递进来的 ref 引用。通过将这个引用在组件中绑定到相应的原生 DOM 元素上,实现了外部直接引用到组件内部元素的目的,所以叫 forwardRef(传递引用)。

使用上面创建的 FancyInput,在组件加载后使其获得焦点:

class App extends Component {constructor(props) {super(props);this.inputRef = React.createRef();}componentDidMount() {if (this.inputRef.current) {this.inputRef.current.focus();}}render() {return (<div className="App">
-        <input type="text" ref={this.inputRef}/>
+        <FancyInput ref={this.inputRef} /></div>);}
}

TypeScript 中传递引用

先看正常情况下,对原生 DOM 元素的引用。还是上面的示例:

class App extends Component<{}, {}> {private inputRef = React.createRef();componentDidMount() {/** ? Object is possibly 'null' */this.inputRef.current.focus();}render() {return (<div className="App">{/* ? Type '{}' is missing the following properties from type 'HTMLInputElement':... */}<input type="text" ref={this.inputRef} /></div>);}
}

像上面那样创建并使用存在两个问题。

一个是提示我们的引用无法赋值到 <input>ref 属性上,类型不兼容。引用需要与它真实所指代的元素类型相符,这正是 TypeScript 类型检查为我们添加的约束。这个约束的好处是,我们在使用引用的时候,就知道这个引用真实的元素类型,TypeScript 会自动提示可用的方法和属性,同时防止调用该元素身上没有的属性和方法。这里修正的方法很简单,如果 hover 或 F12 查看 React.createRef() 的方法签名,会发现它是个泛型方法,支持传递类型参数。

function createRef<T>(): RefObject<T>;

所以上面创建引用时,显式指定它的类型。

- private inputRef = React.createRef();
+ private inputRef = React.createRef<HTMLInputElement>();

第二个问题是即使在 componentDidMount 生命周期中使用,TypeScript 仍然提示 current 的值有可能为空。上面讨论过,其实此时我们知道它不可能为空的。但因为 TypeScript 无法理解 componentDidMount,所以它不知道此时引用其实是可以安全使用的。解决办法当然是加上判空的逻辑。

  componentDidMount() {
+    if(this.inputRef.current){this.inputRef.current.focus();
+    }}

还可通过变量后添加 ! 操作符告诉 TypeScript 该变量此时非空。

  componentDidMount() {
-      this.inputRef.current.focus();
+      this.inputRef.current!.focus();}

修复后完整的代码如下:

class App extends Component<{}, {}> {private inputRef = React.createRef<HTMLInputElement>();componentDidMount() {this.inputRef.current!.focus();}render() {return (<div className="App"><input type="text" ref={this.inputRef} /></div>);}
}

React + TypeScript 组件引用的传递

继续到组件的情况,当需要引用的元素在另一个组件内部时,还是通过 React.forwardRef()

这是该方法的签名:

function forwardRef<T, P = {}>(Component: RefForwardingComponent<T, P>): ForwardRefExoticComponent<PropsWithoutRef<P> & RefAttributes<T>>;

可以看到,方法接收两个类型参数,T 为需要引用的元素类型,我们示例中是 HTMLInputElementP 为组件的 props 类型。

所以添加引用传递后,FancyInput 组件在 TypeScript 中的版本应该长这样:

const FancyInput = React.forwardRef<HTMLInputElement, {}>((props, ref) => {return <input type="text" ref={ref} className="fancy-input" />;
});

使用组件:

class App extends Component<{}, {}> {private inputRef = React.createRef<HTMLInputElement>();componentDidMount() {this.inputRef.current!.focus();}render() {return (<div className="App"><FancyInput ref={this.inputRef} /></div>);}
}

相关资源

  • Refs and the DOM
  • Forwarding Refs
  • findDOMNode()
  • React Refs with TypeScript

转载于:https://www.cnblogs.com/Wayou/p/react_typescript_forwardref.html

React + TypeScript:元素引用的传递相关推荐

  1. 子组件向父组件传递数据_如何将元素引用向下传递到角度的组件树中

    子组件向父组件传递数据 I recently had a requirement to make sure a PrimeNG Dropdown panel inside a modal with s ...

  2. React + TypeScript实战(二)hooks用法

    本文采用的react相关技术为: react@18.2.0 typescript@4.7.4 脚手架create-react-app 一.函数式组建的声明方式 import react, { FC } ...

  3. react组件之间传递信息/react组件之间值的传递

    react组件之间传递信息/react组件之间值的传递 首先咱们先来了解一下,数据是怎么进行相互间传递的; api和组件的区别:一个是逻辑层的方法函数,一个是表现层的组件(方法函数). api是一组预 ...

  4. 【React+TS】从零开始搭建react+typescript+router+redux+less+px2rem自适应+sass+axios反向代理+别名@+Antd-mobile

    一.通过create-react-app脚手架创建项目 npx create-react-app testproject --template typescript 在vscode中打开项目,可以看到 ...

  5. 【React+TS】从零开始搭建react+typescript+router+redux+less+pxToVw自适应+sass+axios反向代理+别名@+Antd-mobile

    一.通过create-react-app脚手架创建项目 npx create-react-app testproject --template typescript  在vscode中打开项目,可以看 ...

  6. React + Typescript + Webpack 开发环境配置

    对于复杂或多人开发的 React 项目来说,管理和使用每个组件的 props . state 或许会成为一件让人头痛的事情,而为每一个组件写文档,成本也会比较大,对项目的开发效率也不是最理想的. Ty ...

  7. React+TypeScript+webpack4多入口项目搭建

    资源 React-16.8.* react-router-dom-4.3.* TypeScript-3.5.* webpack-4.* eslint-5.16.* 项目目录 ├── dist # 打包 ...

  8. web record 前端页面录屏 (react + typescript)

    web record 前端页面录屏 (react + typescript + parcel) 项目地址: https://github.com/bgwd666/web-record 演示: 录屏页面 ...

  9. TypeScript项目引用(project references)

    转发 TypeScript项目引用(project references) TypeScript新特性之项目引用(project references) 项目引用是TypeScript 3.0中的一项 ...

最新文章

  1. 【POJ】3617 Best Cow Line (字典序 字符串)
  2. eplan模板_EPLAN之3D箱柜清单自动生成
  3. 免费Java高级工程师学习资源,使用指南
  4. python是什么语言、即变量不需要显示声明数据类型-python中可以声明变量类型吗...
  5. proe4.0安装教程
  6. 四舍五入_从四舍五入谈起
  7. 第 6-7 课:Java 分布式框架面试题合集
  8. linuxShell之一 文件读取 循环与分支
  9. 比较器matlab,用于比较 MATLAB 对象的公共属性的比较器 - MATLAB - MathWorks 中国
  10. ACM/ICPC 之 BFS+状态压缩(POJ1324(ZOJ1361))
  11. 如何下载使用期刊 LateX 模板
  12. kali免杀工具shellter
  13. 基于IM实现直播礼物效果
  14. 2015人生感悟哲理
  15. linux服务器告警信息:Free inodes is less than xx% on /volume 排查
  16. android ipad 播放器,[AS3]专业级跨平台网页播放器支持PC、iPad、iPhone、Android系统...
  17. Esp8266(WIFI模块)刷阿里云固件
  18. LWIP协议栈[I/drv.emac] RxCpltCallback err = -3错误解决办法
  19. ionic:引入图标
  20. 计算机启动后桌面上什么都没有,电脑开机后,桌面上什么都没有了?我怎么处理?好着急啊...

热门文章

  1. jsp: jstl标签库 uri标签
  2. TCP,IP,HTTP,SOCKET区别和联系
  3. office 2007全屏快捷键|设置
  4. 【Win 10 应用开发】UI Composition 札记(二):基本构件
  5. node实战学习纪录
  6. Web安全1沙箱隔离
  7. Linux(Centos6.5)用户名密码
  8. XMLHTTP使用具体解释
  9. nagios二次开发(一)---开发思想
  10. 关于Domain-Specific Languages