React forwardRef HoC 没有引用容器元素
React forwardRef HoC not giving reference to container element
我正在尝试为关闭元素构建一个通用 HOC,点击它的 space(外部解决方案上的通用关闭)。
据我所知,这可以通过 forwardRef 和 HOC 实现来实现,尽管官方文档中有一个示例,但我似乎无法正确理解。
所以我希望我的 HOC 创建对组件容器的引用。它是包装的,因为它有处理程序来跟踪点击并根据它们采取行动。例如,假设我们有一个通用的 Dropdown 组件,人们会期望我可以在该组件区域之外的任何单击上关闭它。
我目前拥有的代码:
import React from 'react';
function withClose(Component) {
class ClickContainer extends React.Component {
constructor() {
super();
this.handleClose = this.handleClose.bind(this);
}
componentDidMount() {
document.addEventListener('click', this.handleClose);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClose);
}
handleClose(e) {
// I expect having here context of container of wrapped component to do something like
const { forwardedRef } = this.props; // <- I expect having context in forwardedRef variable
}
render() {
const { forwardedRef, ...rest } = this.props;
return <Component ref={forwardedRef} {...rest} />;
}
}
return React.forwardRef((props, ref) => {
return <ClickContainer {...props} forwardedRef={ref} />;
});
}
export default withClose;
我在这里错过了什么?我无法让它工作,我只得到包装组件的上下文而不是元素本身。
非常感谢!
几天前我实现了同样的事情。
我想要一个处理 onClickoutside
的 HOC
我希望该组件检查每次点击是否点击了子项,以及它是否对子项调用了一个函数。
这是我的解决方案:
import React from 'react';
export default function withClickOutside(WrappedComponent) {
class WithClickOutside extends WrappedComponent {
constructor(props) {
super(props);
this.handleClickOutside = this.handleClickOutside.bind(this);
this.wrappedElement = React.createRef();
}
componentDidMount() {
document.addEventListener('click', this.handleClickOutside, true);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, true);
}
handleClickOutside(event) {
if (event.type !== 'click') return;
if (!this.wrappedElement.current) {
throw new Error(`No ref for element ${WrappedComponent.name}. Please create ref when using withClickOutside`);
}
if (!this.wrappedElement.current.contains(event.target)) {
if (!this.onClickOutside) {
throw new Error(`${WrappedComponent.name} does not implement onClickOutside function. Please create onClickOutside function when using withClickOutside`);
}
this.onClickOutside(event);
}
}
render() {
const wrapped = super.render();
const element = React.cloneElement(
wrapped,
{ ref: this.wrappedElement },
);
return element;
}
}
return WithClickOutside;
}
然后您包装的组件必须实现一个名为 onClickOutside
的函数。
Ref 应该传递给元素
结帐https://codesandbox.io/s/7yzoqm747x
假设
export const Popup = (props,) => {
const { name, forwardRef } = props;
return (
<div ref={forwardRef}> // You need to pass it down from props
{name}
</div>
)
}
和 HOC
export function withClose(Component) {
class ClickContainer extends React.Component {
constructor() {
super();
this.handleClose = this.handleClose.bind(this);
}
componentDidMount() {
document.addEventListener('click', this.handleClose);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClose);
}
handleClose(e) {
const { forwardRef } = this.props;
console.log(forwardRef);
}
render() {
const { forwardRef, ...rest } = this.props;
return <Component forwardRef={forwardRef} {...rest} />;
}
}
return React.forwardRef((props, ref) => {
return <ClickContainer {...props} forwardRef={ref} />;
});
}
并期待
const CloseablePopup = withClose(Popup);
class App extends Component {
popupRef = React.createRef();
render() {
return (<CloseablePopup ref={popupRef} name="Closable Popup" />);
}
}
我正在尝试为关闭元素构建一个通用 HOC,点击它的 space(外部解决方案上的通用关闭)。
据我所知,这可以通过 forwardRef 和 HOC 实现来实现,尽管官方文档中有一个示例,但我似乎无法正确理解。
所以我希望我的 HOC 创建对组件容器的引用。它是包装的,因为它有处理程序来跟踪点击并根据它们采取行动。例如,假设我们有一个通用的 Dropdown 组件,人们会期望我可以在该组件区域之外的任何单击上关闭它。
我目前拥有的代码:
import React from 'react';
function withClose(Component) {
class ClickContainer extends React.Component {
constructor() {
super();
this.handleClose = this.handleClose.bind(this);
}
componentDidMount() {
document.addEventListener('click', this.handleClose);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClose);
}
handleClose(e) {
// I expect having here context of container of wrapped component to do something like
const { forwardedRef } = this.props; // <- I expect having context in forwardedRef variable
}
render() {
const { forwardedRef, ...rest } = this.props;
return <Component ref={forwardedRef} {...rest} />;
}
}
return React.forwardRef((props, ref) => {
return <ClickContainer {...props} forwardedRef={ref} />;
});
}
export default withClose;
我在这里错过了什么?我无法让它工作,我只得到包装组件的上下文而不是元素本身。
非常感谢!
几天前我实现了同样的事情。
我想要一个处理 onClickoutside
我希望该组件检查每次点击是否点击了子项,以及它是否对子项调用了一个函数。
这是我的解决方案:
import React from 'react';
export default function withClickOutside(WrappedComponent) {
class WithClickOutside extends WrappedComponent {
constructor(props) {
super(props);
this.handleClickOutside = this.handleClickOutside.bind(this);
this.wrappedElement = React.createRef();
}
componentDidMount() {
document.addEventListener('click', this.handleClickOutside, true);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClickOutside, true);
}
handleClickOutside(event) {
if (event.type !== 'click') return;
if (!this.wrappedElement.current) {
throw new Error(`No ref for element ${WrappedComponent.name}. Please create ref when using withClickOutside`);
}
if (!this.wrappedElement.current.contains(event.target)) {
if (!this.onClickOutside) {
throw new Error(`${WrappedComponent.name} does not implement onClickOutside function. Please create onClickOutside function when using withClickOutside`);
}
this.onClickOutside(event);
}
}
render() {
const wrapped = super.render();
const element = React.cloneElement(
wrapped,
{ ref: this.wrappedElement },
);
return element;
}
}
return WithClickOutside;
}
然后您包装的组件必须实现一个名为 onClickOutside
的函数。
Ref 应该传递给元素
结帐https://codesandbox.io/s/7yzoqm747x
假设
export const Popup = (props,) => {
const { name, forwardRef } = props;
return (
<div ref={forwardRef}> // You need to pass it down from props
{name}
</div>
)
}
和 HOC
export function withClose(Component) {
class ClickContainer extends React.Component {
constructor() {
super();
this.handleClose = this.handleClose.bind(this);
}
componentDidMount() {
document.addEventListener('click', this.handleClose);
}
componentWillUnmount() {
document.removeEventListener('click', this.handleClose);
}
handleClose(e) {
const { forwardRef } = this.props;
console.log(forwardRef);
}
render() {
const { forwardRef, ...rest } = this.props;
return <Component forwardRef={forwardRef} {...rest} />;
}
}
return React.forwardRef((props, ref) => {
return <ClickContainer {...props} forwardRef={ref} />;
});
}
并期待
const CloseablePopup = withClose(Popup);
class App extends Component {
popupRef = React.createRef();
render() {
return (<CloseablePopup ref={popupRef} name="Closable Popup" />);
}
}