相关文章推荐
酷酷的鸵鸟  ·  React中如何动态添加和删除元素_reac ...·  1 月前    · 
慷慨大方的薯片  ·  react ...·  1 周前    · 
曾深爱过的野马  ·  kotlin中使用Date()获取yyyy- ...·  9 月前    · 
火星上的西瓜  ·  C语言定义 二进制 十六进制 普通字符串 ...·  11 月前    · 
不羁的感冒药  ·  如何使用typescript合并具有相同属性 ...·  1 年前    · 
一身肌肉的烤红薯  ·  tkinter treeview 表格边框-掘金·  1 年前    · 
被表白的针织衫  ·  postman运行报错“org.spring ...·  1 年前    · 
Code  ›  React之ref的高阶用法-阿里云开发者社区
const 按钮 阿里 react
https://developer.aliyun.com/article/1052906
焦虑的领结
1 年前
产品 解决方案 文档与社区 免费试用 定价 云市场 合作伙伴 支持与服务 了解阿里云
备案 控制台 登录/注册
开发者社区
首页
探索云世界
新手上云 云上应用构建 云上数据管理 云上探索人工智能
云计算 弹性计算 无影 存储 网络 倚天
云原生 容器 serverless 中间件 微服务 可观测 消息队列
数据库 关系型数据库 NoSQL数据库 数据仓库 数据管理工具 PolarDB开源 向量数据库

热门

Modelscope模型即服务 弹性计算 云原生 数据库 物联网 云效DevOps 龙蜥操作系统 平头哥 钉钉开放平台
大数据 大数据计算 实时数仓Hologres 实时计算Flink E-MapReduce DataWorks Elasticsearch 机器学习平台PAI 智能搜索推荐
人工智能 机器学习平台PAI 视觉智能开放平台 智能语音交互 自然语言处理 多模态模型 pythonsdk 通用模型
开发与运维 云效DevOps 钉钉宜搭 支持服务 镜像站 码上公益
问产品
动手实践
考认证
TIANCHI大赛
活动广场
任务中心 飞天Club技术沙龙 训练营 话题 开发者评测 乘风者计划 阿里云MVP 直播
下载
镜像站 技术资料 插件
本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

forwardRef转发Ref


forwardRef的初衷就是解决ref不能跨层级捕获和传递的问题,forwardRef接受了父级元素标记的ref信息,并把它转发下去,使得子组件可以通过props来接受到上一层级或者更上层级的ref。


场景一: 跨层级获取


比如想要通过标记子组件ref,来获取子组件下的孙组件的某一DOM元素,或者是组件实例。使用 React.forwardRef


场景:想要在GrandFather组件通过标记ref,获取到孙组件Son的组件实例.可以理解为,React.forwardRef将子组件的ref跑出去到顶层。在爷爷组件中可以进行使用


// 孙组件
function Son(Props) {
    const {grandRef} = props
    return <div>
        <div>i am alien</div>
        <span ref={grandRef}>123</span>
// 父组件





    
class Father extends React.Component{
    constructor(props){
        super(props)
    render () {
        return <div>
            <Son grandRef={this.props.grandRef}></Son>
const newFather = React.forwardRef((props,ref) => <Father grandRef={ref} {...props}></Father>)
// 爷组件
class GrandFather extends React.Component {
    constructor(props){
        super(props)
    node = null
    componentDidMount(){
        console.log(this.node)
    render () {
        return <div>
            <NewFather ref={(node) => this.node = node}></NewFather>
}

如上所述:forwardRef把ref变成了可以通过props传递和转发。


官网解释:


React.forwardRef 会创建一个React组件,这个组件能够将其接受的ref属性转发到其组件树下的另一个组件中。


React.forwardRef接受渲染函数作为参数,React将使用props和ref作为参数来调用次函数,此函数返回React节点。


const FancyButton = React.forwardRef((props, ref) => (
  <button ref={ref} className="FancyButton">
    {props.children}
  </button>
// You can now get a ref directly to the DOM button:
const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>;




    

述中,React会将<FancyButton ref={ref}>元素的 ref作为第二个参数传递给React.forwardRef函数中的渲染函数,该渲染函数会将ref 传递给<button ref={ref}> 元素


场景二:合并转发ref


通过forwardRef转发的ref不要理解为只能用来直接获取组件实例,DOM元素,也可以用来传递合并之后的自定义ref。


场景:通过Home绑定ref,来获取子组件Index的实例Index,dom元素button,以及孙组件Form的实例。

// 表单组件
class Form extends React.Component{
    render() {
        return <div>{...}</div>
// index组件
class Index extends React.Component{
    componentDidMount() {
        const {forwardRef} = this.props
        forwardRef,current = {
            form: this.form,
            index: this,
            button: this.button
    form = null
    button = null
    render() {
        return <div>
            <button ref={(button) => this.button = button}>点击</button>
            <Form ref={(form) => this.form = form}></Form>
const ForwardRefIndex = React.forwardRef((props,ref) => <Index {...props} forwardRef={ref} ></Index>)
// home组件
export default function Home() {
    const ref = useRef(null)
    useEffect(() =>  {
        console.log(ref.current)
    },[])
    return <ForwardRefIndex ref={ref}></ForwardRefIndex>





    
}

如上所示:


通过useRef创建了一个ref对象,通过forwardRef将当前ref对象传递给子组件。


向Home 组件传递的ref对象上,绑定form孙组件实例,index子组件实例,和button DOM元素。


场景三:高阶组件转发


如果通过高阶组件包裹一个原始类组件,就会产生一个问题,如果高阶组件HOC没有处理ref,那么由于高阶组件本身会返回一个新的组件,所以当使用HOC包装后组件的时候,标记的ref会指向HOC返回的组件,而并不是HOC包裹的原始类组件,为了解决这个问题,forwardRef可以对HOC做一层处理。


 
function HOC(Component){
  class Wrap extends React.Component{
     render(){
        const { forwardedRef ,...otherprops  } = this.props
        return <Component ref={forwardedRef}  {...otherprops}  />
  return  React.forwardRef((props,ref)=> <Wrap forwardedRef={ref} {...props} /> ) 
class Index extends React.Component{
  render(){
    return <div>hello,world</div>
const HocIndex =  HOC(Index)
export default ()=>{
  const node = useRef(null)
  useEffect(()=>{
    console.log(node.current)  /* Index 组件实例  */ 
  },[])
  return <div><HocIndex ref={node}  /></div>
}

经过forwardRef 处理后的HOC,就可以正常访问到Index组件实例。


声明一个组件Wrap,接收 HOC 传入的组件Index。


使用forwardRef 进行ref转发。


在HocIndex中获取到Index实例。


ref实现组件通讯


在一些场景下不想通过往常的单数据流的方式来改变子组件的更新,拿着时候就可以通过ref模式标记子组件实例。,从而操作子组件。如antd的form表单,对外暴漏出来的 resetFields,setFieldsValue等接口。


类组件


对于类组件可以通过ref直接获取组件实例。实现组件通信

/* 子组件 */
class Son extends React.PureComponent{
    state={
       fatherMes:'',
       sonMes:''
    fatherSay=(fatherMes)=> this.setState({ fatherMes  }) /* 提供给父组件的API */
    render(){
        const { fatherMes, sonMes } = this.state
        return <div className="sonbox" >
            <div className="title" >子组件</div>
            <p>父组件对我说:{ fatherMes }</p>
            <div className="label" >对父组件说</div> <input  onChange={(e)=>this.setState({ sonMes:e.target.value })}   className="input"  /> 
            <button className="searchbtn" onClick={ ()=> this.props.toFather(sonMes) }  >to father</button>
/* 父组件 */
export default function Father(){
    const [ sonMes , setSonMes ] = React.useState('') 
    const sonInstance = React.useRef(null) /* 用来获取子组件实例 */
    const [ fatherMes , setFatherMes ] = React.useState('')
    const toSon =()=> sonInstance.current.fatherSay(fatherMes) /* 调用子组件实例方法,改变子组件state */
    return <div className="box" >
        <div className="title" >父组件</div>
        <p>子组件对我说:{ sonMes }</p>
        <div className="label" >对子组件说</div> <input onChange={ (e) => setFatherMes(e.target.value) }  className="input"  /> 
        <button className="searchbtn"  onClick={toSon}  >to son</button>
        <Son ref={sonInstance} toFather={setSonMes} />
}

父组件使用 props传递值,将子组件给父组件要说的话的方法传递给子组件,供子组件给父组件进行传递。


子组件中写好父组件要给子传递值的方法,。并且将自己的实例通过ref暴漏给父组件,父组件通过暴漏的实例上的对应方法进行传递。


useImperativeHandle 在函数组件中获取子组件ref实例。


它有三个参数:


  • 第一个参数 ref : 接受 forWardRef 传递过来的 ref 。
  • 第二个参数 createHandle :处理函数,返回值作为暴露给父组件的 ref 对象。
  • 第三个参数 deps :依赖项 deps,依赖项更改形成新的 ref 对象。

2f5cf3fe0dcc4a7e93f11f2dc60a7d08.png


流程分析:


上述代码中,父组件用ref标记了子组件ForwarSon,但是子组件Son是函数组件,没有实例返回。所以用forwardRef 转发ref生成了一个新的组件,ForwarSon。


子组件Son用useImperativeHandle接收父组件ref生成Son实例,并将input的方法 onFocus 和改变input输入值的方法 onChange 传递给了ref,对外暴漏了出去。


父组件可以通过ref调用 onFocus 以及 onChangevalue


使用useRef 做函数组件缓存


函数组件每一次render,函数都会上下文重新执行,有一种情况就是,在执行一些事件方法改变数据或者保存新数据的时候,没必要更新视图,这时候就无需放在state中。


useRef 可以创建出一个ref原始对象,只要组件没有销毁,ref对象就一直存在,那么完全可以把一些不依赖于视图更新的数据存储到ref中。


优点:


1.可以直接修改数据,不会造成函数组件冗余的更新作用。


2.useRef保存数据,它始终在当前组件中指向一个内存空间,这样的好处是随时可以访问到变化后的值。


const toLearn = [ { type: 1 , mes:'let us learn React' } , { type:2,mes:'let us learn Vue3.0' }  ]
export default function Index({ id }){
    const typeInfo = React.useRef(toLearn[0])
    const changeType = (info)=>{
        typeInfo.current = info /* typeInfo 的改变,不需要视图变化 */
    useEffect(()=>{
       if(typeInfo.current.type===1){
           /* ... */
    },[ id ]) /* 无须将 typeInfo 添加依赖项  */
    return <div>
            toLearn.map(item=> <button key={item.type}  onClick={ changeType.bind(null,item) } >{ item.mes }</button> )
# 1. 基本概念和语法
React 是基于 JavaScript 的库,用于构建用户界面。它采用虚拟 DOM 技术,能够高效地渲染页面。React 的基本语法包括 JSX、组件、状态管理和生命周期钩子等。
```jsx  
import React from 'react';
class App extends React.Component {  
 constructor(props) {  
   super(props);  
   this.state = {  
     count: 0  
 handleClick = (
Web3-Basketball
 
推荐文章
酷酷的鸵鸟  ·  React中如何动态添加和删除元素_react 动态添加组件
1 月前
慷慨大方的薯片  ·  react 实现点击其他地方,隐藏列表(点击元素外)_react 点击其他地方 弹窗隐藏
1 周前
曾深爱过的野马  ·  kotlin中使用Date()获取yyyy-MM-dd HH:mm:ss格式的当前时间 - CSDN文库
9 月前
火星上的西瓜  ·  C语言定义 二进制 十六进制 普通字符串 转换函数 - 爱吃砂糖橘的白龙 - 博客园
11 月前
不羁的感冒药  ·  如何使用typescript合并具有相同属性但不同值的数组对象?
1 年前
一身肌肉的烤红薯  ·  tkinter treeview 表格边框-掘金
1 年前
被表白的针织衫  ·  postman运行报错“org.springframework.web.servlet.resource.ResourceHttpRequestHandler cannot be cast to or_resourcehttprequesthandler ca
1 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号