Skip to content

Commit 569cd7d

Browse files
committed
fix(datepicker): 优化 picker 组件状态更新逻辑与事件处理
- 改进 getDerivedStateFromProps 中对 open 属性变化的判断逻辑 - componentDidUpdate 中增加 visible 状态一致性检查 - 修复 changeVisible 方法中重复设置状态的问题
1 parent 0b9587a commit 569cd7d

1 file changed

Lines changed: 58 additions & 31 deletions

File tree

src/components/datepicker/common/picker.js

Lines changed: 58 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -24,46 +24,58 @@ class Picker extends Component {
2424

2525
this.state = {
2626
currentValue: value ? formatValue(displayNow(new Date(value)), this.format) : defaultTime,
27-
id: Math.random()
28-
.toString()
29-
.replace('.', ''),
27+
id: Math.random().toString().replace('.', ''),
3028
visible: open,
3129
style: {},
3230
prevProps: props,
33-
checkFlag: true // 校验输入的日期格式是否正确
31+
checkFlag: true, // 校验输入的日期格式是否正确
3432
};
3533

3634
this.inpRef = createRef();
3735
this.popupRef = createRef();
3836

3937
this.containerRef = createRef();
4038

41-
this.setYearChild = ref => {
39+
this.setYearChild = (ref) => {
4240
this.yearChild = ref;
4341
};
44-
this.setYearMonthChild = ref => {
42+
this.setYearMonthChild = (ref) => {
4543
this.yearMonthChild = ref;
4644
};
47-
this.setMonthDayChild = ref => {
45+
this.setMonthDayChild = (ref) => {
4846
this.monthDayChild = ref;
4947
};
50-
this.setDateChild = ref => {
48+
this.setDateChild = (ref) => {
5149
this.dateChild = ref;
5250
};
5351
}
5452

5553
static getDerivedStateFromProps(props, prevState) {
5654
const { prevProps } = prevState;
55+
56+
// 如果是初始化状态(没有 prevProps)
57+
if (!prevProps) {
58+
return {
59+
visible: props.open || false,
60+
prevProps: props,
61+
};
62+
}
63+
5764
const { open } = props;
5865
const { open: prevOpen } = prevProps;
5966

67+
// 只有当 open 属性真正发生变化时才更新状态
6068
if (open !== prevOpen) {
6169
return {
6270
visible: open,
63-
prevProps: props
71+
prevProps: props,
6472
};
6573
}
66-
return null;
74+
75+
// 更新 prevProps 但不改变 visible 状态
76+
return {
77+
prevProps: props,
78+
};
6779
}
6880

6981
componentDidMount() {
@@ -76,12 +88,14 @@ class Picker extends Component {
7688
componentDidUpdate(prevProps) {
7789
const { value: prevValue, open: prevOpen } = prevProps;
7890
const { value, open } = this.props;
79-
const { checkFlag } = this.state;
91+
const { checkFlag, visible } = this.state;
8092
if (prevValue !== value) {
8193
const date = checkFlag && value ? displayNow(new Date(value)) : value;
8294
this.handleValueChange(date, false);
8395
}
84-
if (prevOpen !== open) {
96+
97+
// 只有当 open 属性发生变化且与当前 visible 状态不一致时才调用 changeVisible
98+
if (prevOpen !== open && open !== visible) {
8599
this.changeVisible(open);
86100
}
87101
}
@@ -114,7 +128,7 @@ class Picker extends Component {
114128
const { checkFlag } = this.state;
115129
const value = (output && checkFlag) || isClickBtn ? this.props.formatValue(output) : output || '';
116130
this.setState({
117-
currentValue: value ? value.toString().replace(/-/g, '/') : ''
131+
currentValue: value ? value.toString().replace(/-/g, '/') : '',
118132
});
119133
if (isPop) {
120134
this.props.onChange(value);
@@ -154,15 +168,15 @@ class Picker extends Component {
154168
return <DatePicker ref={this.setDateChild} {...this.props} checkValue={transformObj(checkValue)} onChange={this.onPopChange} />;
155169
};
156170

157-
popClick = evt => {
171+
popClick = (evt) => {
158172
evt.stopPropagation();
159173
if (evt.nativeEvent.stopImmediatePropagation) {
160174
evt.nativeEvent.stopImmediatePropagation();
161175
}
162176
};
163177

164178
// 关闭时 校验输入的是否正确
165-
handleClick = e => {
179+
handleClick = (e) => {
166180
const isClickPicker = this.containerRef.current.contains(e.target) || (this.popupRef.current && this.popupRef.current.contains(e.target));
167181
const { checkFlag, visible, currentValue } = this.state;
168182
const { tempMode, formatValue } = this.props;
@@ -188,14 +202,19 @@ class Picker extends Component {
188202
}
189203
};
190204

191-
changeVisible = isVisible => {
205+
changeVisible = (isVisible) => {
206+
// 防止重复设置相同的状态
207+
if (this.state.visible === isVisible) {
208+
return;
209+
}
210+
192211
const { containerRef } = this;
193212
const { id } = this.state;
194213
const { containerEleClass, height, isAppendToBody, className } = this.props;
195214

196215
if (isVisible && id) {
197216
this.setState({
198-
visible: true
217+
visible: true,
199218
});
200219

201220
const style = this.positionPop();
@@ -209,7 +228,7 @@ class Picker extends Component {
209228
containerRef.current,
210229
<div className={`${selectorClass}-popup ${className}`} ref={this.popupRef} onClick={this.popClick}>
211230
{this.renderMainPop()}
212-
</div>
231+
</div>,
213232
);
214233
}
215234

@@ -229,7 +248,7 @@ class Picker extends Component {
229248
}
230249

231250
this.setState({
232-
visible: false
251+
visible: false,
233252
});
234253
this.props.onClose();
235254
destroyDOM(id, containerRef.current);
@@ -248,18 +267,18 @@ class Picker extends Component {
248267
position: 'fixed',
249268
left: isLocationAlignRight ? `${left - (POPUP_WIDTH - width)}px` : `${left}px`,
250269
top: isLocationTop ? `${top - popupHeight}px` : `${bottom}px`,
251-
marginTop
270+
marginTop,
252271
};
253272
}
254273
return {
255274
top: isLocationTop ? `${-popupHeight}px` : `${height}px`,
256275
left: isLocationAlignRight ? '' : '0px',
257276
right: isLocationAlignRight ? '0px' : '',
258-
marginTop
277+
marginTop,
259278
};
260279
};
261280

262-
onClickInput = e => {
281+
onClickInput = (e) => {
263282
e.stopPropagation();
264283
const { disabled } = this.props;
265284
const { visible } = this.state;
@@ -291,9 +310,8 @@ class Picker extends Component {
291310
currentValueTemp.length > lenRule || currentValueTemp.split('/').length > backslashRule + 1 ? currentValue.toString() : currentValueTemp;
292311

293312
this.setState({
294-
currentValue: currentValueFinal
313+
currentValue: currentValueFinal,
295314
});
296-
297315
// 值改变的时候,日历要显示出来
298316
if (!this.state.visible && currentValueFinal) {
299317
this.changeVisible(true);
@@ -303,7 +321,7 @@ class Picker extends Component {
303321
const checkFlag = currentValueFinal ? checkFormat(currentValueFinal.trim(), tempMode, showTimePicker) : true;
304322

305323
this.setState({
306-
checkFlag
324+
checkFlag,
307325
});
308326

309327
// 校验通过 并且有值 日历选择联动
@@ -318,7 +336,16 @@ class Picker extends Component {
318336
const afterV = currentValueFinal.trim().split(' ')[1]; // 拿到年月日时分秒的数值
319337
const dealData = transformObj(currentValueFinal);
320338
// hour: 'other', minute: 'other', second: 'other' 方式時分秒重置,具體看date-picker/grid.js配合使用
321-
this.dateChild.changeCheckValue(afterV ? dealData : { ...dealData, hour: 'other', minute: 'other', second: 'other' });
339+
this.dateChild.changeCheckValue(
340+
afterV
341+
? dealData
342+
: {
343+
...dealData,
344+
hour: 'other',
345+
minute: 'other',
346+
second: 'other',
347+
},
348+
);
322349
// this.dateChild.changeCheckValue( afterV ? dealData : { ...dealData, hour: null, minute: null, second: null } );
323350
}
324351
}
@@ -354,7 +381,7 @@ class Picker extends Component {
354381
// 校验年月日格式是否正确,正确 补全 校验设置为true;不正确 不补全
355382
returnValue = this.props.formatValue(transformObj(formatValue(displayNow(new Date(`${currentValue.trim()} ${defaultTime}`)), this.format)));
356383
this.setState({
357-
currentValue: returnValue
384+
currentValue: returnValue,
358385
});
359386
}
360387

@@ -381,7 +408,7 @@ class Picker extends Component {
381408
'minDate',
382409
'tempMode',
383410
'formatValue',
384-
'integer'
411+
'integer',
385412
]);
386413

387414
return (
@@ -409,7 +436,7 @@ class Picker extends Component {
409436
<div className={`${selectorClass}-popup ${className}`} ref={this.popupRef} style={{ ...style }} onClick={this.popClick}>
410437
{this.renderMainPop()}
411438
</div>,
412-
this.portal
439+
this.portal,
413440
)}
414441
</div>
415442
);
@@ -427,7 +454,7 @@ Picker.propTypes = {
427454
formatValue: PropTypes.func,
428455
onChange: PropTypes.func,
429456
onClose: PropTypes.func,
430-
canEdit: PropTypes.bool
457+
canEdit: PropTypes.bool,
431458
};
432459

433460
Picker.defaultProps = {
@@ -441,7 +468,7 @@ Picker.defaultProps = {
441468
formatValue: noop,
442469
onChange: noop,
443470
onClose: noop,
444-
canEdit: false
471+
canEdit: false,
445472
};
446473

447474
export default Picker;

0 commit comments

Comments
 (0)