reactjs - pass ref to a class component with React.cloneElement and render prop
问题描述
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.
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).
But if the child is just a DOM
node like a div
for example, it is working as expected.
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>
);
}
}
}
The usage:
class App extends Component {
render() {
return (
<div>
<Parent render={someValue => <div> {someValue}</div>} />
<Parent render={someValue => <Menu someValue={someValue} />} />
</div>
);
}
}
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.
解决方案
我有几乎相同的问题。
我选择使用findDOMNode,你可以在 react-external-click 中react-dom
看到完整的解决方案。
虽然警告说明:
findDOMNode 是一个用于访问底层 DOM 节点的逃生舱口。在大多数情况下,不鼓励使用此逃生舱口,因为它会穿透组件抽象。
findDOMNode 仅适用于已安装的组件(即已放置在 DOM 中的组件)。如果您尝试在尚未安装的组件上调用它(例如在尚未创建的组件上调用 render() 中的 findDOMNode()),则会引发异常。
findDOMNode 不能用于功能组件。
我认为这是应对这一特殊挑战的更好解决方案。
它让您对消费者“透明”,同时能够针对DOM
.
好的,在这里,抓住参考:
componentDidMount() {
this.ref = findDOMNode(this);
// some logic ...
}
这就是我使用没有自己的包装器的渲染函数的方式:
render() {
const { children, render } = this.props;
const { clickedOutside } = this.state;
const renderingFunc = render || children;
if (typeof renderingFunc === 'function') {
return renderingFunc(clickedOutside);
} else {
return null
}
}
}
推荐阅读
- events - 如何在 Tcl/Tk 中绑定“Control-Control”事件
- python - Python - 从日志文件中读取字符串
- google-cloud-platform - 如何将 SQL 转储文件从 Google Cloud Storage 导入 Cloud SQL 作为日常工作?
- powershell - 在其他 DNS 区域中使用别名执行 PowerShell 脚本
- javascript - 如何通过 AngularJS 从 json URL 显示表格?
- c# - 我怎样才能制作HTML。使用 MVC 开始 Form() 工作
- python - 使用 pyspark 将文件夹数据从源位置复制到目标位置
- scala - Scala JVM 调用 Scala JS
- reactjs - 更改 reactstrap UncontrolledCollapse 的默认行为
- c# - 与 VS C++ /ASSEMBLYLINKRESOURCE 类似的 C# 设置