想象一下具有React组件
function List() {
return (<ul>
<li>1</li>
<li>2</li>
</ul>
);
}
我想创建一个高阶组件,例如,修改所有li
节点的样式。
function makeRed(component) {
return function(props) {
const element = React.createElement(component, props);
return React.cloneElement(
element,
element.props,
React.Children.map(
element.props.children,
ch => React.cloneElement(ch, {
...ch.props,
style: {
backgroundColor: "red"
}
},
ch.props.children
)
)
);
}
}
但是。这行不通。孩子们是空的。
有趣的是,如果我直接创建组件,例如
...
const element = <ul><li>1</li><li>2</li></ul>;
...
问题:如何访问任何React元素的子孙?
答案 0 :(得分:1)
正如@hamms所指出的,这是一种反模式。有better ways to implement themes in React个使用普通的旧CSS。
说,这是您的用例的一个实用示例-https://codesandbox.io/s/ymqwyww22z。
基本上,这是我所做的:
使List
为基于类的组件。将功能组件包装到一个组件中并没有太大的麻烦。
import React, { Component } from "react";
export default class List extends Component {
render() {
return (
<ul>
<li>1</li>
<li>2</li>
</ul>
);
}
}
在动态类render
中实施Red<Component>
,首先获取从基本组件的渲染返回的元素树,然后对其进行编辑。
import React from "react";
export default function makeRed(Component) {
return class RedComponent extends Component {
constructor(props) {
super(props);
RedComponent.displayName = `Red${Component.name}`;
}
render() {
let componentElement = super.render();
let { children, ...rest } = componentElement.props;
children = React.Children.map(children, child => {
return React.cloneElement(child, {
...child.props,
style: {
backgroundColor: "red"
}
});
});
return React.cloneElement(componentElement, rest, ...children);
}
};
}
createElement
的{{1}}版本有何不同?当makeRed
返回一个HOC时,在makeRed
组件中使用它时,您无需为其分配道具。像这样...
App
因此在动态组件函数中,您使用function App() {
return <RedList />; // no props!
}
创建新实例的过程中,createElement
不会携带任何子代。由于component.props
创建了自己的子代,因此您需要获取并修改它们,而不是从List
读取子代。