使用React.cloneElement将ref传递给类组件并渲染prop [英] pass ref to a class component with React.cloneElement and render prop

查看:1039
本文介绍了使用React.cloneElement将ref传递给类组件并渲染prop的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个根据其子级ref处理某些内部state的组件(例如,与该子级ref相关的鼠标事件).
该组件使用render-prop将相关的state片段传递给它的子元素,并通过React.cloneElement util附加带有ref的子元素.

I'm writing a component that handle some internal state according to a ref of it's child (a mouse event related to that child's ref for example).
This component is using a render-prop to pass on the relevant piece of state to it's child, and render the child with the ref attached via React.cloneElement util.

问题是,当子级是class组件时,由于某些原因ref不可用,并且由于它是一种类型为function(当然,我克隆了之后).

The problem is that when the child is a class component, for some reason the ref is not available, and i can't find a way to render it as it's a react element object with a type of function (after i clone it of course).

但是,如果子节点只是一个像div这样的DOM节点,则它可以正常工作.

But if the child is just a DOM node like a div for example, it is working as expected.

我的解决方法是检查子类型,如果它是function类型,我将用我自己的div包装克隆的元素,如果它只是一个dom节点,则照原样进行渲染.
但是,我不想用额外的div包裹孩子,因为我不想添加不必要的DOM节点.

My work-around is to check the type of the child, and if it is a type of function I'll wrap the cloned element with my own div, if it's just a dom node then render as is.
However, i would like to not wrap the child with an extra div as i don't want to add unnecessary DOM nodes.

这是一个基本的代码示例,为简洁起见,删除了大多数代码:
父级组件:

Here is a basic code example, most code removed for brevity:
The Parent component:

class Parent extends Component {

    attachRef = node => {
        this.ref = node;
    }

    render() {
        const { render } = this.props;
        const { someValue } = this.state;
        const Child = render(someValue);
        const WithRef = React.cloneElement(Child, {
            ref: this.attachRef
        });
        if (typeof WithRef.type === 'string') { // node element
            return WithRef;
        }
        else if (typeof WithRef.type === 'function') {
            // this is a react element object.. not sure how to render it
            // return ?
        } else {
            // need to find a way to render without a wrapping div
            return (
                <div ref={this.attachRef}>{Child}</div>
            );
        }
    }
}

用法:

class App extends Component {
    render() {
        return (
            <div>
                <Parent render={someValue => <div> {someValue}</div>} />
                <Parent render={someValue => <Menu someValue={someValue} />} />
            </div>
        );
    }
}

当我像第一个示例一样渲染常规DOM节点时,它工作正常,当我尝试渲染Menu(这是一个class组件)时,它如上所述无法工作.

When i render regular DOM nodes like the first example it works fine, when i try to render the Menu (which is a class component) it doesn't work as mentioned above.

推荐答案

我几乎遇到了相同的问题.
我选择使用react-dom中的 findDOMNode ,您可以看到完整的解决方案在react-external-click中 .

I had almost an identical issue.
i chose to use findDOMNode from react-dom, you can see the full solution in react-external-click.

尽管警告提示:

findDOMNode是用于访问基础DOM节点的转义口. 在大多数情况下,不建议使用此逃生舱口,因为它会 破坏了组件的抽象.

findDOMNode is an escape hatch used to access the underlying DOM node. In most cases, use of this escape hatch is discouraged because it pierces the component abstraction.

findDOMNode仅适用于已安装的组件(即, 已放置在DOM中).如果您尝试在组件上调用它 尚未挂载的对象(例如在render()中调用findDOMNode() 在尚未创建的组件上)将出现异常 抛出.

findDOMNode only works on mounted components (that is, components that have been placed in the DOM). If you try to call this on a component that has not been mounted yet (like calling findDOMNode() in render() on a component that has yet to be created) an exception will be thrown.

findDOMNode不能在功能组件上使用.

findDOMNode cannot be used on functional components.

我认为这是解决此特定挑战的更好解决方案.
它使您对使用者透明",同时能够定位DOM中的组件.

I think this is the better solution for this particular challenge.
It let's you be "transparent" to the consumer, while being able to target the component in the DOM.

好,就在这里,拿起裁判:

Ok here it is, grabbing the ref:

componentDidMount() {
    this.ref = findDOMNode(this);
    // some logic ...
}

这是我使用不带包装的渲染函数的方式:

this is how i use a render function with no wrapper of my own:

render() {
        const { children, render } = this.props;
        const { clickedOutside } = this.state;
        const renderingFunc = render || children;

        if (typeof renderingFunc === 'function') {
            return renderingFunc(clickedOutside);
        } else {
            return null
        }
    }
}

这篇关于使用React.cloneElement将ref传递给类组件并渲染prop的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆