React.cloneElement是什么,如何使用,为什么使用

902 阅读3分钟

React.cloneElement是啥

React.cloneElement是React提供的一个API,用于在保留原有props的基础上,克隆一个React元素,并可选地修改新元素的props或children

React.cloneElement(
  element, // 要克隆的React元素,封装组件,对象
  [props], // 可选,新元素要修改的props
  [...children] // 可选,新元素要替换的children,不光是content还有样式和element,type
)

简单举个例子

// 传参确定要修改的属性是color和children
function Button(props) {
  return <button style={{ backgroundColor: props.color }}>{props.children}</button>
}

// 传入自定义元素,和要修改的属性
const newProps = { color: 'red' }
const newButton = React.cloneElement(
                    <Button>Hello World</Button>, 
                    newProps,
                    <h1>我是新元素,带type</h1>
                  )
//用React.cloneElement,通过传入新的props修改原有组件的样式和children
const newButton = React.cloneElement(<Button>Hello World</Button>, newProps)
//用React.cloneElement,通过传入新的props修改原有组件的样式
  • children是指,若传入第三个参数,他会替代element元素及其content,若不传默认就是element元素中的内容 有第三参数.jpg 这个children返回的是对象(跟cloneElement的第三个参数有关)

  • 没有第三个参数,children就是指第一个参数中测content 没有第三个参数.jpg 这个children返回的是值

  • 如果第二个参数不传入,则获取不到props其他数据,只有默认children 第二个参数不参入.jpg 这个children返回的是值

再举个例子

  const NewEle = (props: any) => (
      <div style={{...props.style}}>
          这是自定义的元素{props.children}
      </div>
  )
  
  const CloneEle = ({ dom = <div/>, ...rest }) => {
    const styles = {
      color: 'blue',
      textAlign: 'left',
      fontSize: '20px'
    }
    //要克隆的元素、要更改的属性值进行了封装, 样式和内容进行分开处理
    return React.cloneElement(dom, {style:styles,...{dom.props},...rest})
  }
  // P元素和内容,会替代dom中的默认<div/>, 而封装的styles因为没有可以替代的也会被保留。
  // 而最上面的NewEle子组件,可以把cloneElement里面三个参数的所有数据都获取
 

  const renderEle = () => {
    return (
        <CloneEle dom={<NewEle style={{color: 'red', fontWeight: 'bold'}} />}>
            <p>这是父组件元素</p>
        </CloneEle>
    )
  }
  const NewEle = (props: any) => {
    console.log(props, 888999)
    return <div style={{fontSize:'20px', textAlign: 'left', color: props.color || 'blue'}}>这是自定义的元素{props.children}</div>
  }

  const renderEle = () => {
    const newProps = {color: 'red', fontWeight: 'bold'}
    return React.cloneElement(<NewEle><p>这是父组件元素</p></NewEle>, newProps)
  }

这样理解起来就没有那么困难, 但是第一种写法经过封装,也有它的优势 哪些场景可以用呢,组件扩展复用,但是这种用法可以直接被react组件自身已有的替代

//在子组件中cloumns的operate
<Button onClick={extendOperate.props.onClick} type="link">  {extendOperate.props.children}
</Button>
//父组件中
const extendOperateEle = (
    <Button onClick={() => {console.log(333)}}>我是扩展的Button</Button>)
const cloneTable = React.cloneElement(
    <NewTable
      data={data}
    />, 
    {
      extendOperateEle,
    }
)

//组件本身可替代,
 <NewTable
    data={data}
  >
     <Button onClick={() => {console.log(333)}}>我是扩展的Button</Button>
  </NewTable> 

除了上面封装的元素,另外一种就是下面这种了比较有意义

<ModalButton>
    <Button>我是子元素</Button>
</ModalButton>

const cloneEle = React.cloneElement(props.children, {onClick(){modalVisible = true}}

{cloneEle}
//用React.cloneElement,获取该元素的children--button,对button添加方法, 把方法放到组件内部

哪些场景可以用到呢,与弹窗类似的组件,抽屉,tab切换,等

使用React.cloneElement的优势在于:

  1. 可以避免重复编写类似的组件代码,提高代码复用率。例如,我们可以通过克隆一个Button组件,将其样式改变,然后得到一个新的PrimaryButton组件,而不需要再单独编写一个PrimaryButton组件。
  2. 可以方便地对已有组件进行扩展和修改,而无需修改原有组件代码。例如,我们可以通过克隆一个Button组件,将其添加一个新的props,用于处理点击事件,而不需要修改原有Button组件的代码。 使用React.cloneElement的劣势在于:
  3. React.cloneElement方法存在副作用,即会修改已有组件的props。如果不小心修改了原有组件的props,可能会导致组件功能出现问题。
  4. React.cloneElement方法只能针对已有组件进行修改,无法创建新的组件。如果需要创建新的组件,仍需要手动编写新的组件代码。

链接: www.jianshu.com/p/be2f22e6b…