React上下文使用者如何访问消费组件上的ref



我已经使用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的forwardRefAPI可以实现我想要的目标。唯一需要的更改是更换

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'));

最新更新