Ref的高阶用法
1.forwardRef 转发 Ref
1.跨层级获取
场景 : 想要在GrandFather组件通过标记ref,来获取孙组件Son的组件实例
import * as React from 'react';
interface ISonProps {
grandRef:React.ForwardedRef<HTMLElement>
}
//孙组件
function Son(props:ISonProps){
const {grandRef} = props
return (
<div>
<div>I am Son</div>
<span ref={grandRef}>这个是想要获取的元素</span>
</div>
)
}
//父组件
interface IFatherProps {
grandRef:React.ForwardedRef<HTMLElement>
}
class Father extends React.Component<IFatherProps>{
constructor(props:IFatherProps){
super(props)
}
render(): React.ReactNode {
return(
<div>
<Son grandRef={this.props.grandRef}></Son>
</div>
)
}
}
const NewFather = React.forwardRef((props,ref:React.ForwardedRef<HTMLElement>)=><Father grandRef={ref} {...props} />)
interface IGrandFather {}
class GrandFather extends React.Component<IGrandFather>{
constructor(props:IGrandFather){
super(props)
}
node:HTMLElement|null = null
componentDidMount(){
console.log(this.node) //打印想要获取的元素
}
render(): React.ReactNode {
return(
<div>
<NewFather ref={(node)=>this.node=node} />
</div>
)
}
}
export default GrandFather
2.合并转发Ref
场景 : 通过Home绑定ref,来获取子组件Index的实例Index,dom元素的Button,以及孙组件Form的实例
import * as React from 'react';
class Form extends React.Component{
render(): React.ReactNode {
return(
<form>
<label htmlFor="username">用户名</label>
<input type="text" id='username' />
</form>
)
}
}
interface IIndexProps {
forwardRef:React.ForwardedRef<HTMLElement>
}
class Index extends React.Component<IIndexProps>{
componentDidMount(){
const {forwardRef} = this.props
forwardRef.current = {
form:this.form,
index:this,
button:this.button
}
}
form:Form|null = null
button:HTMLElement|null = null
render(){
return(
<div>
<button ref={(button)=>this.button=button}>点击</button>
<Form ref={(form)=>this.form=form}></Form>
</div>
)
}
}
const ForwardRefIndex = React.forwardRef((props,ref:React.ForwardedRef<HTMLElement>)=><Index {...props} forwardRef={ref}/>)
export default function Home(){
const ref = React.useRef(null)
React.useEffect(()=>{
console.log(ref.current);
},[])
return <ForwardRefIndex ref={ref}/>
}
3.高阶组件转发
import * as React from 'react';
function HOC(Component){
interface IWrapProps{
forwardedRef:React.ForwardedRef<HTMLElement>
}
class Wrap extends React.Component<IWrapProps>{
render(): React.ReactNode {
const {forwardedRef,...otherProps} = this.props
return (
<Component ref={forwardedRef} {...otherProps} />
)
}
}
return React.forwardRef((props,ref:React.ForwardedRef<HTMLElement>)=><Wrap forwardedRef={ref} {...props} />)
}
class Index extends React.Component{
render(): React.ReactNode {
return (
<div>Hello World</div>
)
}
}
const HocIndex = HOC(Index)
export default function Pages(){
const node = React.useRef(null)
React.useEffect(()=>{
console.log(node.current)
},[])
return (
<div><HocIndex ref={node} /></div>
)
}
2.Ref实现组件通信
1.类组件 ref
import * as React from 'react';
interface ISonProps{
toFather:React.Dispatch<React.SetStateAction<string>>
}
class Son extends React.PureComponent<ISonProps>{
state={
fatherMsg:"",
sonMsg:""
}
fatherSay = (fatherMsg:string)=>this.setState({fatherMsg})
render(): React.ReactNode {
const {fatherMsg,sonMsg} = this.state
return(
<div className='son-box'>
<div className='title'>子组件</div>
<p>父组件对我说:{fatherMsg}</p>
<div className='label'>对父组件说</div>
<input type="text" onChange={e=>this.setState({sonMsg:e.target.value})} className="input"/>
<button className='search-btn' onClick={()=>this.props.toFather(sonMsg)}>to Father</button>
</div>
)
}
}
export default function Father(){
const [sonMsg,setSonMsg] = React.useState('')
const sonInstance = React.useRef(null)
const [fatherMsg,setFatherMsg] = React.useState('')
const toSon = ()=>sonInstance.current.fatherSay(fatherMsg)
return(
<div className='box'>
<div className="title">父组件</div>
<p>子组件对我说:{sonMsg}</p>
<div className="label">对子组件说</div>
<input type="text" onChange={e=>setFatherMsg(e.target.value)} className="input" />
<button className='search-btn' onClick={toSon}>to Son</button>
<Son ref={sonInstance} toFather={setSonMsg} />
</div>
)
}
2.forwardRef + useImperativeHandle
import * as React from 'react';
function Son(props,ref){
const inputRef = React.useRef(null)
const [inputValue,setInputValue] = React.useState('')
React.useImperativeHandle(ref,()=>{
const handleRefs = {
onFocus(){
inputRef.current.focus()
},
onChangeValue(value){
setInputValue(value)
}
}
return handleRefs
},[])
return (
<div>
<input type="text" placeholder='请输入内容' ref={inputRef} value={inputValue} />
</div>
)
}
const ForwardSon = React.forwardRef(Son)
export default function Index(){
let curSon = null
let handerClick=()=>{
const {onFocus,onChangeValue} = curSon
onFocus()
onChangeValue("let us learn React")
}
return (
<div>
<ForwardSon ref={cur=>curSon=cur} />
<button onClick={handerClick}>操控子组件</button>
</div>
)
}