refactor: RadioGroup's cloneElement to context (#5453)

This commit is contained in:
Wei Zhu 2017-03-23 17:19:50 +08:00 committed by Benjy Cui
parent 50e5cd3459
commit ab6e521ea2
3 changed files with 66 additions and 30 deletions

View File

@ -1,7 +1,6 @@
import React from 'react';
import React, { PropTypes } from 'react';
import classNames from 'classnames';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import assign from 'object-assign';
import shallowEqual from 'shallowequal';
function getCheckedValue(children) {
let value = null;
@ -36,6 +35,11 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
static defaultProps = {
disabled: false,
};
static childContextTypes = {
radioGroup: PropTypes.any,
};
constructor(props) {
super(props);
let value;
@ -51,6 +55,17 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
value,
};
}
getChildContext() {
return {
radioGroup: {
onChange: this.onRadioChange,
value: this.state.value,
disabled: this.props.disabled,
},
};
}
componentWillReceiveProps(nextProps) {
if ('value' in nextProps) {
this.setState({
@ -65,9 +80,13 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
}
}
}
shouldComponentUpdate(...args) {
return PureRenderMixin.shouldComponentUpdate.apply(this, args);
shouldComponentUpdate(nextProps, nextState, nextContext) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState) ||
!shallowEqual(this.context.group, nextContext.group);
}
onRadioChange = (ev) => {
const lastValue = this.state.value;
const { value } = ev.target;
@ -84,18 +103,7 @@ export default class RadioGroup extends React.Component<RadioGroupProps, any> {
}
render() {
const props = this.props;
const children = !props.children ? [] : React.Children.map(props.children, (radio: any) => {
if (radio && radio.type && (radio.type.__ANT_RADIO || radio.type.__ANT_RADIO_BUTTON) && radio.props) {
return React.cloneElement(radio, assign({}, radio.props, {
onChange: this.onRadioChange,
checked: this.state.value === radio.props.value,
disabled: radio.props.disabled || this.props.disabled,
}));
}
return radio;
});
const { prefixCls = 'ant-radio-group', className = '' } = props;
const { prefixCls = 'ant-radio-group', className = '', children } = props;
const classString = classNames(prefixCls, {
[`${prefixCls}-${props.size}`]: props.size,
}, className);

View File

@ -1,7 +1,7 @@
import RcRadio from 'rc-radio';
import React from 'react';
import React, { PropTypes } from 'react';
import classNames from 'classnames';
import PureRenderMixin from 'rc-util/lib/PureRenderMixin';
import shallowEqual from 'shallowequal';
export interface RadioProps {
/** 指定当前是否选中*/
@ -20,23 +20,35 @@ export interface RadioProps {
}
export default class Radio extends React.Component<RadioProps, any> {
static __ANT_RADIO = true;
static Group: any;
static Button: any;
static defaultProps = {
prefixCls: 'ant-radio',
};
shouldComponentUpdate(...args) {
return PureRenderMixin.shouldComponentUpdate.apply(this, args);
static contextTypes = {
radioGroup: PropTypes.any,
};
shouldComponentUpdate(nextProps, nextState, nextContext) {
return !shallowEqual(this.props, nextProps) ||
!shallowEqual(this.state, nextState) ||
!shallowEqual(this.context.radioGroup, nextContext.radioGroup);
}
render() {
const { prefixCls, className, children, style, ...restProps } = this.props;
let radioProps: RadioProps = { ...restProps };
if (this.context.radioGroup) {
radioProps.onChange = this.context.radioGroup.onChange;
radioProps.checked = this.props.value === this.context.radioGroup.value;
radioProps.disabled = this.props.disabled || this.context.radioGroup.disabled;
}
const wrapperClassString = classNames({
[`${prefixCls}-wrapper`]: true,
[`${prefixCls}-wrapper-checked`]: restProps.checked,
[`${prefixCls}-wrapper-disabled`]: restProps.disabled,
[`${prefixCls}-wrapper-checked`]: radioProps.checked,
[`${prefixCls}-wrapper-disabled`]: radioProps.disabled,
}, className);
return (
@ -46,7 +58,10 @@ export default class Radio extends React.Component<RadioProps, any> {
onMouseEnter={this.props.onMouseEnter}
onMouseLeave={this.props.onMouseLeave}
>
<RcRadio {...restProps} prefixCls={prefixCls} />
<RcRadio
{...radioProps}
prefixCls={prefixCls}
/>
{children !== undefined ? <span>{children}</span> : null}
</label>
);

View File

@ -1,20 +1,33 @@
import React from 'react';
import React, { PropTypes } from 'react';
import Radio from './radio';
export interface RadioButtonProps {
value: string | number;
style?: React.CSSProperties;
disabled?: boolean;
checked?: boolean;
onChange?: (e: any) => any;
}
export default class RadioButton extends React.Component<RadioButtonProps, any> {
static __ANT_RADIO_BUTTON = true;
static defaultProps = {
prefixCls: 'ant-radio-button',
};
static contextTypes = {
radioGroup: PropTypes.any,
};
render() {
let radioProps: RadioButtonProps = { ...this.props };
if (this.context.radioGroup) {
radioProps.onChange = this.context.radioGroup.onChange;
radioProps.checked = this.props.value === this.context.radioGroup.value;
radioProps.disabled = this.props.disabled || this.context.radioGroup.disabled;
}
return (
<Radio {...this.props} />
<Radio {...radioProps} />
);
}
}