react提供的这个方法克隆组件的方法,可能我们在平常的开发中用的很少,主要可能是我们并不知道或者并不了解这个方法。因为我在之前react的children文章中用到过,所以我就进行了一系列的测试,发现真的非常的好用。我们同样使用一些小的demo来介绍他的功能。
React.cloneElement()接收三个参数第一个参数接收一个ReactElement,可以是真实的dom结构也可以是自定义的。第二个参数返回旧元素的props、key、ref。可以添加新的props,第三个是props.children,不指定默认展示我们调用时添加的子元素。如果指定会覆盖我们调用克隆组件时里面包含的元素。接下来我们开始测试
function CloneDemo(props){
return React.cloneElement(<div/>,props,<p>这是一个克隆的元素</p>)
}
export default CloneDemo;
我先写了一个最简单的demo,克隆的元素div和给他添加的子元素p都正常展示了。接着测试他的功能,接着上面的例子
function CloneDemo(props){
return React.cloneElement(<div/>,props,<p>这是参数传入的元素</p>)
}
function ContainerBox(){
return <CloneDemo><h1>这是在父组件添加的元素</h1></CloneDemo>
}
export default ContainerBox;
我对代码进行了调整,增加了一个ContainerBox组件,并调用了克隆的元素,还给他添加了子元素,查看效果:
发现传入的参数元素覆盖了从父组件传入的元素,导致h1标签并没有被渲染。因为平常开发我们写公共组件可能从父组件传入的比较多,所以下面的例子都不传入第三个参数。
上面是直接渲染了一个div显然这样的写法很不友好,可能我们想渲染一个p元素,一个a元素甚至是一个自定义的,上面的写法显然已经不支持了,下面进行修改:
function CloneDemo({dom=<div/>,...props}){
return React.cloneElement(dom,{...props})
}
function ContainerBox(){
return <CloneDemo dom={<p></p>}><h1>这是在父组件添加的元素</h1></CloneDemo>
}
export default ContainerBox;
给克隆组件传入了一个dom,dom接收一个ReactElement,还给他赋予了一个默认值,如果没传入渲染div即可,我先给dom传入了一个p元素查看页面元素:
传入的p元素正常显示出来了。下来测试自定义的ReactElement看是否正常渲染
const Exam = (props) => <div>这是一个自定义的ReactElement元素{props.children}</div>
function CloneDemo({dom=<div/>,...rest}){
return React.cloneElement(dom,{...rest})
}
function ContainerBox(){
return <CloneDemo dom={<Exam style={{color: "red",textAlign: "center"}} />}><h1>这是在父组件添加的元素</h1></CloneDemo>
}
export default ContainerBox;
我创建了一个Exam组件,并将他传给克隆组件,我们还给他加上了样式查看效果:
可以正常显示但是发现样式并没有生效,接下来处理样式,主要需要两部分的样式,一部分是克隆的时候直接给的样式,一个是传入的组件的样式,处理原则是如果样式冲突,采用传入的样式。
const Exam = (props) => {
return <div style={{...props.styles,...props.style}}>这是一个自定义的ReactElement元素{props.children}</div>
}
function CloneDemo({dom=<div/>, ...rest }){
const styles = {
color: "blue",
minWidth: "1200px",
margin: "100px auto",
textAlign: "left"
}
return React.cloneElement(dom,{styles, ...rest})
}
function ContainerBox(){
return <CloneDemo dom={<Exam style={{color: "red",textAlign: "center"}} />}><h1>这是在父组件添加的元素</h1></CloneDemo>
}
export default ContainerBox;
我将CloneDemo中定义的styles,已经传入Exam组件时给他定义的样式都加到了Exam组件身上
继续优化克隆组件
const Exam = (props) => {
return <div style={{...props.style}}>这是一个自定义的ReactElement元素{props.children}</div>
}
function CloneDemo({dom=<div/>, ...rest }){
const styles = {
color: "blue",
minWidth: "1200px",
margin: "100px auto",
textAlign: "left"
}
return React.cloneElement(dom,{
style: Object.assign({}, styles, dom.props.style), //将传入的样式放到最后提高他的优先级
...rest
})
}
function ContainerBox(){
return <CloneDemo dom={<Exam style={{color: "red",textAlign: "center"}} />}><h1>这是在父组件添加的元素</h1></CloneDemo>
}
export default ContainerBox;
这样在Exam组件中只需要传入一个props.style样式就可以了。