React - 组件复合

2020-08-14  本文已影响0人  闪电西兰花
// src/components/Composition.js
import React from 'react'

// Dialog作为容器不关心内容和逻辑,只负责提供外层样式
// 插入的内容{props.children}可理解为vue中的slot
function Dialog (props) {
  return (  
    <div style={{ border: "4px solid red"}}>
      {/* children是固定写法 */}
      {props.children}
    </div>
  )
}

// WelcomeDialog组件通过复合提供内容
function WelcomeDialog (props) {
  return (
    <Dialog>
      <h1>welcome</h1>
      <p>感谢使用</p>
    </Dialog>
  )
}

export default function () {
  return (
    <div>
      <WelcomeDialog></WelcomeDialog>
    </div>
  )
}
复合组件WelcomeDialog.jpg
// src/components/Composition.js
import React from 'react'

function Dialog (props) {
  return (  
    // 边框默认颜色为red,如果有配置则获取配置颜色
    <div style={{ border: `4px solid ${props.color || 'red'}` }}>
      {/* children是固定写法 */}
      {props.children}
    </div>
  )
}

function WelcomeDialog (props) {
  return (
    <Dialog {...props}>
      <h1>welcome</h1>
      <p>感谢使用</p>
    </Dialog>
  )
}

export default function () {
  return (
    <div>
      <WelcomeDialog color={'blue'}></WelcomeDialog>
    </div>
  )
}
// src/components/Composition.js
import React from 'react'

// 这里可以看出props.children、props.footer都可以是JSX
// props.children可以写成任意的Js表达式
function Dialog (props) {
  return (  
    // 边框默认颜色为red,如果有配置则获取配置颜色
    <div style={{ border: `4px solid ${props.color || 'red'}` }}>
      {/* children是固定写法 */}
      {props.children}
      {/* 具名插槽 footer */}
      <div className="footer">
        {props.footer}
      </div>
    </div>
  )
}

export default function () {
  let footer = <button onClick={() => {alert('confirm')}}>this is footer</button>
  return (
    <div>
      <WelcomeDialog color={'blue'} footer={footer}></WelcomeDialog>
    </div>
  )
}
// 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 (
    <div>
      <Fetcher name="getUser"> 
        // 因为props.children是个函数,所以在这里直接调用
        {({name, age}) => (
          <p>{name} - {age}</p>
        )}
      </Fetcher>
    </div>
  )
}
// src/components/Composition.js
import React from 'react'

function Filter (props) {
  return (
    <div>
      {React.Children.map(props.children, child => {
        if(child.type !== props.type) {
          return;
        }
        // return过滤之后的数组
        return child;
      })}
    </div>
  )
}

export default function () {
  return (
    <div>
      {/* 过滤器 过滤出指定标签*/}
      <Filter type="h5">
        <h5>re</h5>
        <h5>eae</h5>
        <p>this is p</p>
      </Filter>
    </div>
  )
}
// src/components/Composition.js
import React from 'react'

// 修改children
function RadioGroup (props) {
  return (
    <div>
      {/* RadioGroup遍历自己的children,并分别给他们加上相同的name属性 */}
      {React.Children.map(props.children, child => {
        // vdom不可更改,必须先clone一个再做更改
        // 不可以写成 child.props.name = props.name
        return React.cloneElement(child, {name:props.name})
      })}
    </div>
  )
}

function Radio ({children, ...rest}) {
  // 因为Radio组件中还有内容,所以要特别处理children
  // 将传进来的props分成2部分,分别是children和其他属性
  return (
    <label>
      <input type="radio" {...rest}></input>
      {children}
    </label>
  )
}

export default function () {
  return (
    <div>
      <RadioGroup name="mvvm">
        <Radio value="vue">vue</Radio>
        <Radio value="react">react</Radio>
        <Radio value="angular">angular</Radio>
      </RadioGroup>
    </div>
  )
}
上一篇 下一篇

猜你喜欢

热点阅读