关于react.js:React-父组件如何主动联系子组件

4次阅读

共计 2689 个字符,预计需要花费 7 分钟才能阅读完成。

在典型的 React 数据流中,props 是父子组件交互的惟一形式。要批改一个子组件,须要应用新的 props 从新渲染它。然而,在某些状况下,须要在典型数据流之外被动查看或强制批改子组件,这时候就须要应用 Refs,将 DOM Refs 裸露给父组件。

何时应用 Refs

上面是几个适宜应用 refs 的状况:

  • 治理焦点,文本抉择或媒体播放;
  • 触发强制动画;
  • 集成第三方 DOM 库;
  • 测量子 DOM 节点的大小或地位;

防止应用 refs 来做任何能够通过申明式实现来实现的事件,因为它会突破组件的封装。

Refs 与组件

默认状况下,ref 属性必须指向一个 DOM 元素或 class 组件,不能在函数组件上应用 ref 属性,因为它们没有实例。如果须要在函数组件中应用 ref,能够应用 forwardRef,或者将该组件转化为 class 组件。

React.forwardRef

React.forwardRef(props, ref)

  • 第二个参数 ref 只在应用 React.forwardRef 定义组件时存在。惯例函数和 class 组件不接管 ref 参数,且 props 中也不存在 ref
  • Ref 转发不仅限于 DOM 组件,也能够转发 refs 到 class 组件实例中。

Ref 转发

如果应用 16.3 以上版本的 React,应用 ref 转发将 DOM Refs 裸露给父组件。Ref 转发使组件能够像裸露本人的 ref 一样裸露子组件的 ref。如果对子组件的实现没有控制权的话,只能应用 findDOMNode(),但在严格模式下已被废除且不举荐应用。

实现 Ref 转发形式:

  • ref 和 forwardRef
  • useImperativeHandle 和 forwardRef

ref 和 forwardRef

  • 父组件创立 ref,并向下传递给子组件
  • 子组件通过 forwardRef 来获取传递给它的 ref
  • 子组件拿到 ref并向下转发该 ref 到本人的某一个元素上
  • 父组件通过 ref.current 获取绑定的 DOM 元素实例

毛病

  • 会把绑定 ref 元素的 DOM 间接裸露给了父组件
  • 父组件拿到 DOM 后能够进行任意的操作

例子

上面的例子应用的是 React 16.6 引入的 useRef Hook,如果是 React 16.3 版本应用 React.createRef() API,如果更早之前的版本,应用回调模式的 refs。

// 子组件
import React, {forwardRef, useState} from 'react'

const BaseInfo = forwardRef((props, ref) => {console.log('BaseInfo --- props', props)
  console.log('BaseInfo --- ref', ref)

  const [name, setName] = useState('')
  const [age, setAge] = useState('')

  return (<div ref={ref}>
      姓名:
      <input onChange={val => setName(val)} />
      年龄:<input onChange={val => setAge(val)} />
    </div>
  )
})
// 父组件
import React, {useRef} from 'react'
import BaseInfo from './BaseInfo'

function RefTest() {const baseInfoRef = useRef(null)

  const getBaseInfo = () => {console.log('getBaseInfo --- baseInfoRef', baseInfoRef.current)
  }

  return (
    <>
      <BaseInfo
        dataSource={{name: '混沌'}}
        ref={baseInfoRef}
      />
      <button onClick={getBaseInfo}> 获取根本信息 </button>
    </>
  )
}

输入


点击“获取根本信息”按钮后:

useImperativeHandle 和 forwardRef

useImperativeHandle 介绍

useImperativeHandle(ref, createHandle, [deps])

应用 ref 时通过 useImperativeHandle 自定义裸露给父组件的实例值。

通过 useImperativeHandle, 将父组件传入的 ref 和 useImperativeHandle 第二个参数返回的对象绑定到了一起。

长处

  • 只裸露给父组件须要用到的 DOM 办法;
  • 在父组件中, 调用 xxxRef.current 时,返回的是对象;

例子

// 子组件
const OtherInfo = (props, ref) => {console.log('OtherInfo --- props', props)
  console.log('OtherInfo --- ref', ref)

  const inputRef = useRef()
  const [school, setSchool] = useState('')

  useImperativeHandle(ref, () => {console.log('useImperativeHandle --- ref', ref)
    return ({focus: () => {inputRef.current.focus()
      },
      getSchool: () => {return inputRef.current.value}
    })
  }, [inputRef])

  return (
    <div>
      学校:
      <input ref={inputRef} onChange={val => setSchool(val)}/>
    </div>
  )
}

export default forwardRef(OtherInfo)
// 父组件
import React, {useRef} from 'react'
import OtherInfo from './OtherInfo'

function RefTest() {const otherInfoRef = useRef(null)

  const getOtherInfo = () => {console.log('getOtherInfo --- otherInfoRef', otherInfoRef.current)
    console.log('getOtherInfo --- otherInfoRef --- getSchool', otherInfoRef.current.getSchool())
  }

  return (
    <>
      <OtherInfo
        dataSource={{school: '大学'}}
        ref={otherInfoRef}
      />
      <button onClick={getOtherInfo}> 获取其余信息 </button>
    </>
  )
}

输入

正文完
 0