import * as React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import shallowEqual from 'shallowequal'; import Radio from './radio'; import { RadioGroupProps, RadioGroupState, RadioChangeEvent } from './interface'; function getCheckedValue(children: React.ReactNode) { let value = null; let matched = false; React.Children.forEach(children, (radio: any) => { if (radio && radio.props && radio.props.checked) { value = radio.props.value; matched = true; } }); return matched ? { value } : undefined; } export default class RadioGroup extends React.Component { static defaultProps = { disabled: false, prefixCls: 'ant-radio', buttonStyle: 'outline', }; static childContextTypes = { radioGroup: PropTypes.any, }; constructor(props: RadioGroupProps) { super(props); let value; if ('value' in props) { value = props.value; } else if ('defaultValue' in props) { value = props.defaultValue; } else { const checkedValue = getCheckedValue(props.children); value = checkedValue && checkedValue.value; } this.state = { value, }; } getChildContext() { return { radioGroup: { onChange: this.onRadioChange, value: this.state.value, disabled: this.props.disabled, name: this.props.name, }, }; } componentWillReceiveProps(nextProps: RadioGroupProps) { if ('value' in nextProps) { this.setState({ value: nextProps.value, }); } else { const checkedValue = getCheckedValue(nextProps.children); if (checkedValue) { this.setState({ value: checkedValue.value, }); } } } shouldComponentUpdate(nextProps: RadioGroupProps, nextState: RadioGroupState) { return !shallowEqual(this.props, nextProps) || !shallowEqual(this.state, nextState); } onRadioChange = (ev: RadioChangeEvent) => { const lastValue = this.state.value; const { value } = ev.target; if (!('value' in this.props)) { this.setState({ value, }); } const onChange = this.props.onChange; if (onChange && value !== lastValue) { onChange(ev); } } render() { const props = this.props; const { prefixCls, className = '', options, buttonStyle } = props; const groupPrefixCls = `${prefixCls}-group`; const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, { [`${groupPrefixCls}-${props.size}`]: props.size, }, className); let children: React.ReactChildren[] | React.ReactElement[] | React.ReactNode = props.children; // 如果存在 options, 优先使用 if (options && options.length > 0) { children = options.map((option, index) => { if (typeof option === 'string') { // 此处类型自动推导为 string return ( {option} ); } else { // 此处类型自动推导为 { label: string value: string } return ( {option.label} ); } }); } return (
{children}
); } }