我已经使用React的新上下文API构建了一个更高阶的组件,我正在努力寻找一种方法来访问包装的子组件的引用(通过ref()
)。
tl/dr:本质上,我想将ref从Consumer
转发到实际组件。
下面是一个具体的例子。RootComponent
设置CoolProvider
的值,该值假定在所有封装的子组件上公开。使用withCool()
封装子组件,使得它可以访问props.cool
。(当然,在现实世界的例子中,一切都要复杂得多,有几十个组件。)
现在,无论是否已经封装了子组件,我都希望能够通过ref()
获得对它的引用,如RootComponent
所示,但不幸的是,封装的组件不再支持ref()
,因为它们是功能性的!
查看此实时演示(https://jsfiddle.net/64t0oenz/3/)并检查web控制台。您将看到,只有未封装组件的回调才会触发。
我的问题是:有没有办法将引用请求从CoolConsumer
转发到实际组件,以便父组件可以访问它的引用?
const { Provider: CoolProvider, Consumer: CoolConsumer } = React.createContext();
const withCool = Component => props => (
<CoolConsumer>
{cool => <Component {...props} cool={cool} />}
</CoolConsumer>
);
class ChildComponent extends React.Component {
render() {
return this.props.cool ? (
<div>Isn't this cool?</div>
) : (
<div>Not so cool!</div>
);
}
}
const CoolChildComponent = withCool(ChildComponent);
class RootComponent extends React.Component {
render() {
return (
<CoolProvider value={true}>
<ChildComponent ref={(c) => { console.log('Normal child ref', c); }}/>
<CoolChildComponent ref={(c) => { console.log('Cool child ref', c); }}/>
</CoolProvider>
);
}
}
ReactDOM.render(<RootComponent />, document.querySelector('#cool'));
我想通了!使用React的forwardRef
API可以实现我想要的目标。唯一需要的更改是更换
const withCool = Component => props => (
<CoolConsumer>
{cool => <Component {...props} cool={cool} />}
</CoolConsumer>
);
带有
const withCool = Component => React.forwardRef((props, ref) => (
<CoolConsumer>
{cool => <Component {...props} cool={cool} ref={ref} />}
</CoolConsumer>
));
以下是修改后的现场演示:https://jsfiddle.net/64t0oenz/4/打开开发控制台,您现在将看到2个控制台日志打印对普通和酷组件的引用。
ref
就像key
一样,它不是道具
const { Provider: CoolProvider, Consumer: CoolConsumer } = React.createContext();
const withCool = Component => props => {
const {myRef, ...rest} = props;
return (
<CoolConsumer>
{cool => <Component ref={myRef} {...rest} cool={cool} />}
</CoolConsumer>
)
};
class ChildComponent extends React.Component {
render() {
return this.props.cool ? (
<div>Isn't this cool?</div>
) : (
<div>Not so cool!</div>
);
}
}
const CoolChildComponent = withCool(ChildComponent);
class RootComponent extends React.Component {
render() {
return (
<CoolProvider value={true}>
<ChildComponent ref={(c) => { console.log('Normal child ref', c); }}/>
<CoolChildComponent myRef={(c) => { console.log('Cool child ref', c); }}/>
</CoolProvider>
);
}
}
ReactDOM.render(<RootComponent />, document.querySelector('#cool'));