这是我参与第五届青训营伴学笔记创作活动的第四天
ref的高阶用法
1.forwardRef
转发ref
forwardRef 接受了父级元素标记的 ref 信息,并把它转发下去,使得子组件可以通过 props 来接受到上一层级或者是更上层级的ref
使用场景:
- 跨层级获取(爷组件想要获取孙组件的一个Node实例)
- 合并转发ref
- 高阶组件的转发
2.ref实现组件通信
使用场景
- 类组件ref(直接通过ref获取即可)
- 函数组件(通过
forwardRef
+useImperativeHandle
)(因为函数组件没有实例)
// 子组件
function Son (props,ref) {
const inputRef = useRef(null)
const [ inputValue , setInputValue ] = useState('')
useImperativeHandle(ref,()=>{
const handleRefs = {
onFocus(){ /* 声明方法用于聚焦input框 */
inputRef.current.focus()
},
onChangeValue(value){ /* 声明方法用于改变input的值 */
setInputValue(value)
}
}
return handleRefs
},[])
return <div>
<input placeholder="请输入内容" ref={inputRef} value={inputValue} />
</div>
}
const ForwarSon = forwardRef(Son)
// 父组件
class Index extends React.Component{
cur = null
handerClick(){
const { onFocus , onChangeValue } =this.cur
onFocus() // 让子组件的输入框获取焦点
onChangeValue('let us learn React!') // 让子组件input
}
render(){
return <div style={{ marginTop:'50px' }} >
<ForwarSon ref={cur => (this.cur = cur)} />
<button onClick={this.handerClick.bind(this)} >操控子组件</button>
</div>
}
}
3.函数组件缓存数据
原理:useRedf
可以创建出一个ref原始对象,只要组件不销毁,ref对象一直存在,因此可以将不依赖于视图更新的数据存储到ref对象中
Ref的原理
逻辑流程图
只有当fiber
初始化时或者ref对象的指向改变的时候,会执行这一逻辑更新图。
更新是同步还是异步
batchUpdate批量更新,异步并不是使用了Promise
等异步方法,其实本身执行的过程和代码都是同步的,但是合成事件和生命周期的调用顺序在更新之前,导致没法立刻拿到更新后的值,形成了形式上的异步
内部通过一个变量——isBatchingUpdates
来判断是否批量更新
持续更新~~
总结
setState
只是在合成事件和生命周期中是异步的,在原生事件和setTimeout
中都是同步的(例如通过addEventListener
监听事件)