Skip to content

Commit

Permalink
fix(Tag): fix state not matching props (#614)
Browse files Browse the repository at this point in the history
* fix(Tag): fix state not matching props
- derive checked state from props
- polyfill getDerivedStateFromProps
  • Loading branch information
jdkahn authored Apr 28, 2019
1 parent 1cba940 commit 52d09dd
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 2 deletions.
25 changes: 24 additions & 1 deletion docs/tag/demo/selectable.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ const dataSource = ['selectable tag', 'I like orange', 'small tag', 'disabled',

class Demo extends React.Component {
state = {
value: ['I like orange', 'disabled & checked']
value: ['I like orange', 'disabled & checked'],
singleValue: 'selectable tag'
};

handleChange(name, checked) {
Expand All @@ -38,6 +39,13 @@ class Demo extends React.Component {
this.setState({value: next});
}

handleChangeSingle(name, checked) {
const {singleValue} = this.state;
const next = checked ? name : '';

this.setState({singleValue: next});
}

renderTagList(props) {
const {value} = this.state;

Expand All @@ -51,13 +59,28 @@ class Demo extends React.Component {
));
}

renderTagListSingle(props) {
const {singleValue} = this.state;

return dataSource.map((name, i) => (
<SelectableTag key={name}
checked={singleValue === name}
disabled={i > 2}
size={i === 2 ? 'small' : undefined}
onChange={this.handleChangeSingle.bind(this, name)}
{...props}>{name}</SelectableTag>
));
}

render() {
return (
<div className="tag-list">
<h4>type: 'default'</h4>
<TagGroup>{this.renderTagList({type: 'normal'})}</TagGroup>
<h4>type: 'primary'</h4>
<TagGroup>{this.renderTagList({type: 'primary'})}</TagGroup>
<h4>Controlled Tags: Only one selected at a time</h4>
<TagGroup>{this.renderTagListSingle({type: 'normal'})}</TagGroup>
</div>
);
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"classnames": "^2.2.3",
"hoist-non-react-statics": "^2.1.0",
"prop-types": "^15.6.0",
"react-lifecycles-compat": "^3.0.4",
"react-transition-group": "^2.2.1",
"shallow-element-equals": "^1.0.1"
},
Expand Down
13 changes: 12 additions & 1 deletion src/tag/selectable.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { polyfill } from 'react-lifecycles-compat';
import { obj, func } from '../util';
import Tag from './tag';

Expand Down Expand Up @@ -51,6 +52,16 @@ class Selectable extends Component {
bindCtx(this, ['handleClick']);
}

static getDerivedStateFromProps(props, state) {
if (props.checked !== undefined && props.checked !== state.checked) {
return {
checked: props.checked,
};
}

return null;
}

handleClick(e) {
e && e.preventDefault();
// IE9 不支持 pointer-events,还是可能会触发 click 事件
Expand Down Expand Up @@ -97,4 +108,4 @@ class Selectable extends Component {
}
}

export default Selectable;
export default polyfill(Selectable);
9 changes: 9 additions & 0 deletions test/tag/index-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,15 @@ describe('TagCheckable', () => {
const wrapper = mount(<TagCheckable checked />);
assert(wrapper.find('.next-tag').hasClass('checked'));
});

it('should update `checked` state when new props', () => {
const wrapper = mount(<TagCheckable checked/>);

wrapper.setProps({
checked: false
})
assert(wrapper.children().first().state('checked') === false)
});
});

describe('behavior', () => {
Expand Down

0 comments on commit 52d09dd

Please sign in to comment.