有没有办法告诉哪个组件生成了特定的DOM节点?例如
CustomDiv
<div />
只是一个生成<div data-reactid=".0.0.$/=11">a</div>
<div data-reactid=".0.0.$/=12">b</div>
<div data-reactid=".0.0.$/=13">c</div>
元素的包装器。
在DOM中,这些表示为:
CustomDiv
有没有办法告诉DecoratorComponent
组件生成了哪些DOM节点?
上下文:
我有render
包装它装饰的组件的DecoratorComponent
方法。 let Foo;
Foo = class extends React.Component {
render () {
return <div>
<SomeOtherComponent />
{['a', 'b', 'c'].map((letter) => { return <p>{letter}</p> })}
</div>;
}
};
Foo = DecoratorComponent(Foo);
然后修改生成的DOM。
DecoratorComponent
但是,SomeOtherComponent
必须仅修改目标组件生成的DOM,即它应排除{['a', 'b', 'c'].map((letter) => { return <p>{letter}</p> })}
的输出。
我需要找到一种方法来区分在组件中动态生成的DOM(本例中为Foo
)和由doInBackground
组件中的另一个组件生成的DOM。
答案 0 :(得分:5)
您可以使用React Developer Tools检查哪些DOM节点已由哪个React组件呈现。
此外,请查看./src/renderers/dom/client/ReactMount.js
,这是用于管理DOM节点及其与React组件的关系的<C>
<A>
。请注意,react-dom
属性在源代码中称为Object
。
答案 1 :(得分:0)
我建议你不要直接操纵DOM。可以通过一些预防措施,但它可能会降低性能,并可能引入难以发现的错误。让我提出一些想法来解决你在反应空间中的任务。
让我们从最简单的开始吧。我猜你试过这样的事情:
const Foo = (props) => (
<div>
<SomeOtherComponent />
{['a', 'b', 'c'].map((letter) => { return <Decorator><p>{letter}</p></Decorator> })}
</div>
);
如果你需要一次操作列表元素 - 你可以用这种方式包装它们:
const Foo = (props) => (
<Decorator>
<SomeOtherComponent />
{['a', 'b', 'c'].map((letter) => { return <p>{letter}</p> })}
</Decorator>
);
装饰器组件可以访问子反应元素。例如,我们可以将除SomeOtherComponent
的实例之外的所有内容都加粗const Decorator = (props) => (
<div>
{ React.Children.toArray(props.children).map(child =>
child.type === SomeOtherComponent ? child : <b key={child.key}>{child}</b>
)}
</div>
);
如果你想进一步决定在靠近应用程序根目录的地方使用哪个装饰器,你可以简单地将装饰器组件作为道具传递
<Foo decorator={Bolderator}/>
const Foo = ({decorator: Decorator}) => (
<Decorator>
<SomeOtherComponent />
{['a', 'b', 'c'].map((letter) => { return <p>{letter}</p> })}
</Decorator>
);
答案 2 :(得分:0)
关于哪个组件通过挖掘React组件实例内部结构来呈现哪些可以找到的数据,但是你说你想要一个DOM节点并找出哪个React组件呈现它,这个有点难。
你真的需要在 React刷新之后操作DOM ,或者你满足于修改React元素(从JSX / React.createElement
调用返回)在呈现给DOM之前发生了什么?无论哪种方式,拦截render
自己允许您检查元素并用它做你想做的事情。由于子复合组件不会在以后扩展到真正的DOM节点,因此您只能得到您关心的组件。
这是一个装饰器的示例,它将为给定类呈现的每个元素添加一个属性:
function recursiveAddProps(elem, extraProps) {
if (!elem) return;
if (typeof elem === "string") {
// strings get turned into spans
return React.createElement("span", extraProps, elem);
}
const props = elem.props || {};
const newChildren = React.Children.map(props.children, child =>
recursiveAddProps(child, extraProps)
)
return React.cloneElement(elem, extraProps, newChildren);
}
function DecoratorComponent(klass) {
const oldRender = klass.prototype.render;
klass.prototype.render = function() {
const elem = oldRender.apply(this, arguments);
const name = this.constructor.displayName || this.constructor.name;
return recursiveAddProps(elem, {
className: "myOverriddenClass" // this will set className on every element
});
};
return klass;
}
使用这些组件
class Foo extends React.Component {
render() {
return (
<div>
<div>Hi!</div>
<SomeOtherComponent />
{['a', 'b', 'c'].map(letter => <div>{letter}</div> )}
</div>
);
}
}
Foo = DecoratorComponent(Foo);
class SomeOtherComponent extends React.Component {
render() {
return (
<ul>
<li>Some</li>
<li>Other</li>
<li>Component</li>
</ul>
);
}
}
代码导致DOM:
<div class="myOverriddenClass" data-reactid=".0">
<div class="myOverriddenClass" data-reactid=".0.$/=10">
<span class="myOverriddenClass" data-reactid=".0.$/=10.$/=10">Hi!</span>
</div>
<ul data-reactid=".0.$/=11">
<li data-reactid=".0.$/=11.0">Some</li>
<li data-reactid=".0.$/=11.1">Other</li>
<li data-reactid=".0.$/=11.2">Component</li>
</ul>
<div class="myOverriddenClass" data-reactid=".0.$/=12=20">
<span class="myOverriddenClass" data-reactid=".0.$/=12=20.$/=10">a</span>
</div>
<div class="myOverriddenClass" data-reactid=".0.$/=12=21">
<span class="myOverriddenClass" data-reactid=".0.$/=12=21.$/=10">b</span>
</div>
<div class="myOverriddenClass" data-reactid=".0.$/=12=22">
<span class="myOverriddenClass" data-reactid=".0.$/=12=22.$/=10">c</span>
</div>
</div>
您可以看到该类已添加到的每个元素中,除了由SomeOtherComponent
呈现的那些元素 - ul
和li
。
如果您想在DOM节点上设置一些特殊属性,以便您可以识别Foo
组件是否呈现它,您可以指定data-
属性,React会将其刷新到DOM。
<div data-rendered-by="Foo" data-reactid=".0">
<div data-rendered-by="Foo" data-reactid=".0.$/=10">
<span data-rendered-by="Foo" data-reactid=".0.$/=10.$/=10">Hi!</span>
</div>
<ul data-reactid=".0.$/=11">
<li data-reactid=".0.$/=11.0">Some</li>
<li data-reactid=".0.$/=11.1">Other</li>
<li data-reactid=".0.$/=11.2">Component</li>
</ul>
<div data-rendered-by="Foo" data-reactid=".0.$/=12=20">
<span data-rendered-by="Foo" data-reactid=".0.$/=12=20.$/=10">a</span>
</div>
<div data-rendered-by="Foo" data-reactid=".0.$/=12=21">
<span data-rendered-by="Foo" data-reactid=".0.$/=12=21.$/=10">b</span>
</div>
<div data-rendered-by="Foo" data-reactid=".0.$/=12=22">
<span data-rendered-by="Foo" data-reactid=".0.$/=12=22.$/=10">c</span>
</div>
</div>
此处每个DOM节点都有一个data-rendered-by="Foo"
属性,允许您单独告诉DOM该节点是由Foo
呈现的。
Here's a working example:https://jsbin.com/tuliqu/edit?js,output
这是一个非常强大的抽象,可能允许你在不触及DOM的情况下做你想做的事情;例如,在React CSS Modules中,没有触及DOM - the components are simply extended and render is overridden。
答案 3 :(得分:0)
你的问题似乎让某些术语感到困惑,所以我首先要澄清我是如何理解它的。
我有
DecoratorComponent
包装它装饰的组件的render
方法。DecoratorComponent
然后修改生成的DOM。
直接装饰render
方法和&#34;修改生成的DOM&#34;是两件非常不同的事情。 render
方法不会返回DOM片段,它会生成ReactElement
。确定ReactElement
表示DOM元素或React组件是否(在大多数情况下)非常简单 - 在前一种情况下type
是String
,而在其他情况下({{1}在后者中。}或Function
)。
Class
但是,如果您没有直接装饰function decorateRender(render) {
const el = render();
el.props.children = React.Children.map(
el.props.children,
(child, idx) => (typeof child.type === 'string')
? <div className="wrapper">{child}</div>
: child
);
return el;
}
并且您确实在尝试修改生成的已装载DOM,则默认情况下无法将DOM元素链接回其生产者。在开发环境中,您可以尝试h4ck React内部并找到链接(请参阅React Developer Tools),但在生产环境中没有任何反向链接。在React&#34;虚拟DOM&#34;中,DOM只是一种产品,之前就是神奇的事物。当然,您可以随时扩展render
以在渲染时使用自定义数据属性标记元素。