组件源码——按钮组ButtonGroup

ButtonGroup组建的API如下:

属性类型说明
valuestring | number当前值
defaultValuestring | number同 value,不可控
onChangefunc选中事件,参数返回被选中的值

ButtonGroup组件主要是根据children通过findAllByType函数来找出子组件中的所有Button组件,然后利用React.cloneElement为每个Button添加ButtonGroup中的属性,比如key onClick

class ButtonGroup extends Component {

  constructor(props) {
    super(props)
    this.state = {
      value: 'value' in props ? props.value : props.defaultValue
    }
  }

  componentWillReceiveProps(nextProps) {
    'value' in nextProps && this.setState({
      value: nextProps.value
    })
  }

  render() {
    const { className, children, defaultValue, ...other } = this.props
    const items = findAllByType(children, Button)
    const buttons = items.map((item, index) => {
      if (!item) return
      return React.cloneElement(item, {
        key: index,
        type: (item.props.value == this.state.value) ? '' : 'minor',
        onClick: e => {
          e.stopPropagation()
          this.handleClick(item.props.value)
        }
      })
    })
    return (
      <div className={classnames('bfd-button-group', className)} {...other}>
        {buttons}
      </div>
    )
  }

  handleClick(value) {
    this.setState({
      value
    })
    this.props.onChange && this.props.onChange(value)
  }
}

ButtonGroup.propTypes = {
  // 当前值
  value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  // 同 value,不可控
  defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
  // 选中事件,参数返回被选中的值
  onChange: PropTypes.func,
  customProp(props) {
    if ('value' in props && !props.onChange) {
      return new Error('You provided a `value` prop without an `onClick` handler')
    }
  }
}
export default ButtonGroup
复制代码

这里需要注意的是state中value,这个属性是每个button组件的值,而不是名字,上面的value第一个作用是用来在onChange函数作为输出,第二是用来根据item.prop.vaule===this.state.value来判断当前点击的是哪一个按钮,从而让其为默认的primary按钮,而其他未点击的为minor按钮。

我们来看看封装的findAllByType函数

import React from 'react'

function isArray(v) {
  return Object.prototype.toString.call(v) === '[object Array]'
}

const getDisplayName = (Comp) => {
  if (!Comp) {
    return ''
  }
  if (typeof Comp === 'string') {
    return Comp
  }
  return Comp.displayName || Comp.name || 'Component'
}
const findAllByType = (children, type) => {
  const result = []
  let types = []
  if (isArray(type)) {
    types = type.map(t => getDisplayName(t))
  } else {
    types = [getDisplayName(type)]
  }
  React.Children.forEach(children, child => {
    const childType = child && child.type && (child.type.displayName || child.type.name)
    if (types.indexOf(childType) !== -1) {
      result.push(child)
    }
  })
  return result
}
export default findAllByType
复制代码
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值