React - 组件复合

  • 组件复合 - Composition,是另一种区别于高阶组件的一种对扩展组件的方式,可以理解为Vue中的slot
  • 下面我们有一个 Diaolog组件,作为容器,只规定了外层样式,具体的插入的内容由插入的组件决定
// src/components/Composition.js
import React from 'react'

// Dialog作为容器不关心内容和逻辑,只负责提供外层样式
// 插入的内容{props.children}可理解为vue中的slot
function Dialog (props) {
  return (  
    
{/* children是固定写法 */} {props.children}
) } // WelcomeDialog组件通过复合提供内容 function WelcomeDialog (props) { return (

welcome

感谢使用

) } export default function () { return (
) }
复合组件WelcomeDialog.jpg
  • Dialog 组件设置的边框颜色可以改成可配置的
// src/components/Composition.js
import React from 'react'

function Dialog (props) {
  return (  
    // 边框默认颜色为red,如果有配置则获取配置颜色
    
{/* children是固定写法 */} {props.children}
) } function WelcomeDialog (props) { return (

welcome

感谢使用

) } export default function () { return (
) }
  • 复合组件也可以像Vue中一样使用具名插槽,在组件中插入的这部分内容对应显示在容器组件同名的位置
// src/components/Composition.js
import React from 'react'

// 这里可以看出props.children、props.footer都可以是JSX
// props.children可以写成任意的Js表达式
function Dialog (props) {
  return (  
    // 边框默认颜色为red,如果有配置则获取配置颜色
    
{/* children是固定写法 */} {props.children} {/* 具名插槽 footer */}
{props.footer}
) } export default function () { let footer = return (
) }
  • 前面说了 props.chilrdren 可以是任意Js表达式,所以 props.chilrdren 肯定可以是一个函数,然后我们用函数的形式模拟Vue中的作用域插槽
// src/components/Composition.js
import React from 'react'

// 模拟这里是异步调用
const Api = {
  getUser() {
    return {name: 'asher', age: 3}
  }
}

function Fetcher (props) {
  // 通过组件传进来的属性调用api获取数据
  let user = Api[props.name]();
  // 这里的props.children是个函数
  return props.children(user)
}

export default function () {
  return (
    
// 因为props.children是个函数,所以在这里直接调用 {({name, age}) => (

{name} - {age}

)}
) }
  • 再试一试 props.children 是一个数组的时候,做一个简单的过滤器
// src/components/Composition.js
import React from 'react'

function Filter (props) {
  return (
    
{React.Children.map(props.children, child => { if(child.type !== props.type) { return; } // return过滤之后的数组 return child; })}
) } export default function () { return (
{/* 过滤器 过滤出指定标签*/}
re
eae

this is p

) }
  • 复合组件中还可以修改 children,这里我们做一个单选按钮组件,我们都知道同组单选按钮要想实现单选必须拥有相同的 name 属性,这里我们需要实现这个 name属性由父组件 RadioGroup 决定并传递给每一个子组件 Radio
// src/components/Composition.js
import React from 'react'

// 修改children
function RadioGroup (props) {
  return (
    
{/* RadioGroup遍历自己的children,并分别给他们加上相同的name属性 */} {React.Children.map(props.children, child => { // vdom不可更改,必须先clone一个再做更改 // 不可以写成 child.props.name = props.name return React.cloneElement(child, {name:props.name}) })}
) } function Radio ({children, ...rest}) { // 因为Radio组件中还有内容,所以要特别处理children // 将传进来的props分成2部分,分别是children和其他属性 return ( ) } export default function () { return (
vue react angular
) }

你可能感兴趣的:(React - 组件复合)