React数据流中,父组件可以传递 props 给子组件,如果要修改子组件里面的这些 props ,只能通过修改父组件的状态,从而更新子组件里面的 props,就能够更新子组件。如果遇到了需要操作一个真实的DOM元素的时候(如输入框聚焦、选中、触发动画),则可以使用Refs。
一. DOM 添加 refs
class RefButton extends React.Component{
render(){
return <>
<button
ref={element => this.element = element}
onClick={() => console.log(this.element)}
}>
点击打印选中元素
</button>
</>
}
}
ReactDOM.render(<RefButton />,document.getElementById('root'));
- 打印结果是 DOM 元素 button 。所以我们只要对类实例绑定了 button 的 element 进行操作,这就相当于直接对 DOM 元素进行操作。
- ref 的回调会在 render 时执行,也就是 componentDidMount 和 componentDidUpdate 之前执行。
二. 转发 refs 到 DOM
const RefButton = React.forwardRef((props,ref) => <>
<button ref={ref}>{props.children}</button>
</>
)
const ref = React.createRef();
<RefButton ref={ref}>点击(props.children传递)</RefButton>
- RefButton 第二个参数只有在用 React.forwardRef 定义时才会存在,常规函数和 class 组件不接受 ref 参数, props 种也不存在 ref。
三. 高阶组件中转发 refs
const ref = React.createRef();
function packageFunction(Component){
class PackageClass extends React.Component{
render(){
const {refProps,...restProps} = this.props;
return <Component ref={refProps} {...restProps}></Component>
}
}
// 返回被类包装的组件
return React.forwardRef((props, ref) => {
return <PackageClass {...props} refProps={ref} />;
});
}
- 如果不使用 forwardRef 传递 ref,把 ref 传递给 PackageClass 的话,ref 是不会传递给 PackageClass 包裹的组件的,因为 props 不包含 ref 且 ref 没有参数用来进行传递,此时 ref 是指向 PackageClass ,如果对 ref 进行操作,相当于对 PackageClass 进行操作。
- 通过使用 forwardRef ,把它作为 props 传递给 PackageClass ,被包裹的组件就可以接收到包含了 ref 的 props,此时把它传递给包裹组件的 ref ,就实现了高阶组件的传递。