1 高阶组件概念
https://react.docschina.org/docs/higher-order-components.html.
2 Refs概念
https://react.docschina.org/docs/refs-and-the-dom.html.
3 高阶组件中转发Refs
结合官方文档给出的代码https://react.docschina.org/docs/forwarding-refs.html.我们来分析一下。 首先给出一个高阶组件logProps
import React from 'react'
function logProps(WrappedComponent) {
const WrappedComponentName=WrappedComponent.displayName || WrappedComponent.name
class LogProps extends React.Component {
componentDidUpdate(prevProps) {
console.log(WrappedComponentName+'->old props:', prevProps);
console.log(WrappedComponentName+'->new props:', this.props);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return LogProps;
}
export default logProps
然后是FancyButton 组件
import React from 'react'
import logProps from './logProps'
class FancyButton extends React.Component {
sayHi(){
alert("Hello React")
}
render(){
return <button onClick={this.props.onClick}>FancyButton:{this.props.title}</button>
}
}
export default logProps(FancyButton);
我们在APP.js文件中创造Ref对象,然后检查Ref的值,这里便会发现文档中提到的的问题:
"refs 将不会透传下去。这是因为 ref 不是 prop 属性。就像 key 一样,其被 React 进行了特殊处理。如果你对 HOC 添加 ref,该 ref 将引用最外层的容器组件,而不是被包裹的组件。"
class App extends React.Component{
constructor(){
super()
this.state={
title:"ABC"
}
this.fancyButtonRef= React.createRef()
}
handleClickFancyButton=()=>{
this.setState({
title:123
})
console.log("this.fancyButtonRef->",this.fancyButtonRef)
}
render(){
return (
<div className="App">
<FancyButton title={this.state.title}
onClick={this.handleClickFancyButton}
ref={this.fancyButtonRef}/>
</div>
);
}
}
于是官方文档修改了高阶组件logProps 部分代码,如下:
...
render() {
const {forwardedRef, ...rest} = this.props;
return <WrappedComponent ref={forwardedRef} {...this.props} />;
}
return React.forwardRef((props, ref) => {
return <LogProps {...props} forwardedRef={ref} />;
});
4代码背后的数据流程
读到这我已经开始不理解了,查阅了相关资料后,有了如下的理解: (1)最外层(APP.js)传入自定义的Ref对象
<FancyButton title=ref={this.fancyButtonRef}/>
(2)logProps 组件中通过自带函数拿到Ref值,拿到Ref值后对logProps 组件重新绑定,此时拥有Ref对象的属性叫做forwardedRef
function forwardedRef(props,ref){
return <LogProps {...props}
forwardedRef={ref} />;
}
(3)重新绑定过后,便来到真实包装的组件,本例是logProps 组件中的真实包装组件WrappedComponent 。然后把ref的值重新传进去(相当于A传B,B传C,数据都是一样的)
render() {
const {forwardedRef, ...rest} = this.props;
return <WrappedComponent ref={forwardedRef} {...this.props} />;
(4)拿到了包裹组件后,我们就可以在最外层直接调用包裹组件里面的方法,本例中是sayHi()
APP.js
handleClickFancyButton=()=>{
this.setState({
title:123
})
this.fancyButtonRef.current.sayHi()
|