From 52d09dd3e6f59d66d1c494be70cb1760c0a1ca9b Mon Sep 17 00:00:00 2001 From: jdkahn Date: Sun, 28 Apr 2019 16:54:25 +0800 Subject: [PATCH] fix(Tag): fix state not matching props (#614) * fix(Tag): fix state not matching props - derive checked state from props - polyfill getDerivedStateFromProps --- docs/tag/demo/selectable.md | 25 ++++++++++++++++++++++++- package.json | 1 + src/tag/selectable.jsx | 13 ++++++++++++- test/tag/index-spec.js | 9 +++++++++ 4 files changed, 46 insertions(+), 2 deletions(-) diff --git a/docs/tag/demo/selectable.md b/docs/tag/demo/selectable.md index ca3f899781..11830876f1 100644 --- a/docs/tag/demo/selectable.md +++ b/docs/tag/demo/selectable.md @@ -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) { @@ -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; @@ -51,6 +59,19 @@ class Demo extends React.Component { )); } + renderTagListSingle(props) { + const {singleValue} = this.state; + + return dataSource.map((name, i) => ( + 2} + size={i === 2 ? 'small' : undefined} + onChange={this.handleChangeSingle.bind(this, name)} + {...props}>{name} + )); + } + render() { return (
@@ -58,6 +79,8 @@ class Demo extends React.Component { {this.renderTagList({type: 'normal'})}

type: 'primary'

{this.renderTagList({type: 'primary'})} +

Controlled Tags: Only one selected at a time

+ {this.renderTagListSingle({type: 'normal'})}
); } diff --git a/package.json b/package.json index 18393b8262..8363f9e87b 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/tag/selectable.jsx b/src/tag/selectable.jsx index c04ce104f8..34372057b8 100644 --- a/src/tag/selectable.jsx +++ b/src/tag/selectable.jsx @@ -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'; @@ -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 事件 @@ -97,4 +108,4 @@ class Selectable extends Component { } } -export default Selectable; +export default polyfill(Selectable); diff --git a/test/tag/index-spec.js b/test/tag/index-spec.js index 5abf494d7e..a47ce77d9f 100644 --- a/test/tag/index-spec.js +++ b/test/tag/index-spec.js @@ -105,6 +105,15 @@ describe('TagCheckable', () => { const wrapper = mount(); assert(wrapper.find('.next-tag').hasClass('checked')); }); + + it('should update `checked` state when new props', () => { + const wrapper = mount(); + + wrapper.setProps({ + checked: false + }) + assert(wrapper.children().first().state('checked') === false) + }); }); describe('behavior', () => {