Skip to content

Commit f40c564

Browse files
authored
Merge pull request #923 from thundersdata-frontend/rn-issue
fix: 修复Toast和Passcode组件的bug
2 parents cedcea3 + c7c10df commit f40c564

File tree

10 files changed

+75
-70
lines changed

10 files changed

+75
-70
lines changed

.changeset/odd-eyes-fry.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@td-design/react-native': patch
3+
---
4+
5+
修复Toast和Passcode组件的bug

packages/react-native-picker/src/picker/components/Normal/index.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ function NormalPicker<T>(props: ImperativeModalChildrenProps<NormalPickerProps<T
1313
const {
1414
title,
1515
data,
16+
request,
1617
value,
1718
onChange,
1819
cancelText = '取消',
@@ -22,18 +23,15 @@ function NormalPicker<T>(props: ImperativeModalChildrenProps<NormalPickerProps<T
2223
...restProps
2324
} = props;
2425

25-
console.log(value, 'value');
26-
27-
const initialValue = data.length > 0 ? data[0].value : undefined;
28-
29-
const { selectedValue, handleOk, handleChange, handleClose } = useNormalPicker({
26+
const { selectedValue, handleOk, handleChange, handleClose, options } = useNormalPicker({
27+
data,
28+
request,
3029
value,
31-
initialValue,
3230
onChange,
3331
closeModal,
3432
});
3533

36-
if (data.length === 0) return null;
34+
if (options.length === 0) return null;
3735

3836
return (
3937
<>
@@ -61,7 +59,7 @@ function NormalPicker<T>(props: ImperativeModalChildrenProps<NormalPickerProps<T
6159
</Pressable>
6260
</Flex>
6361
<Box height={px(200)}>
64-
<WheelPicker {...restProps} data={data} value={selectedValue} onChange={handleChange} />
62+
<WheelPicker {...restProps} data={options} value={selectedValue} onChange={handleChange} />
6563
</Box>
6664
</>
6765
);

packages/react-native-picker/src/picker/components/Normal/useNormalPicker.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import { NormalPickerProps } from '../../type';
66

77
export default function useNormalPicker<T>({
88
value,
9-
initialValue,
109
onChange,
1110
closeModal,
12-
}: ImperativeModalChildrenProps<Omit<NormalPickerProps<T>, 'data'> & { initialValue?: T }>) {
11+
}: ImperativeModalChildrenProps<Omit<NormalPickerProps<T>, 'data'>>) {
12+
const initialValue = data.length > 0 ? data[0].value : undefined;
13+
1314
const [selectedValue, selectValue] = useSafeState<T | undefined>(value || initialValue);
1415

1516
const handleChange = (val: PickerData<T>) => {

packages/react-native-picker/src/picker/type.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,21 @@ import { CascadePickerItemProps, WheelPickerPropsBase } from '../components/Whee
22

33
export interface PickerProps<T> extends WheelPickerPropsBase {
44
/** 选择项列表 */
5-
data: CascadePickerItemProps<T>[];
5+
data?: CascadePickerItemProps<T>[];
6+
/** 请求数据 */
7+
request?: () => Promise<CascadePickerItemProps<T>[]>;
68
/** 是否级联 */
79
cascade?: boolean;
810
/** 展示几列 */
911
cols?: number;
1012
value?: T[] | T;
1113
onChange?: (value?: T extends (infer U)[] ? U[] : T) => void;
14+
/** 字段名 */
15+
fieldNames?: {
16+
label?: string;
17+
value?: string;
18+
children?: string;
19+
};
1220
}
1321

1422
/** 弹窗Picker的属性 */

packages/react-native/src/passcode/PasscodeItem.tsx

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { forwardRef, memo, RefObject, useEffect } from 'react';
1+
import React, { forwardRef, memo } from 'react';
22
import { Platform, StyleSheet, TextInput } from 'react-native';
33

44
import { useTheme } from '@shopify/restyle';
@@ -18,9 +18,9 @@ const PasscodeItem = forwardRef<TextInput, PasscodeItemProps>(
1818
inputContainerStyle,
1919
focusStyle,
2020
inputStyle,
21-
handleTextChange,
2221
inputValue,
2322
handleKeyPress,
23+
handleChangeText,
2424
selectTextOnFocus,
2525
...rest
2626
},
@@ -29,13 +29,6 @@ const PasscodeItem = forwardRef<TextInput, PasscodeItemProps>(
2929
const theme = useTheme<Theme>();
3030
const [focused, { setTrue, setFalse }] = useBoolean(false);
3131

32-
useEffect(() => {
33-
(ref as RefObject<TextInput>)?.current?.setNativeProps({
34-
value: inputValue,
35-
text: inputValue,
36-
});
37-
}, [inputValue]);
38-
3932
const styles = StyleSheet.create({
4033
input: {
4134
textAlign: 'center',
@@ -61,8 +54,8 @@ const PasscodeItem = forwardRef<TextInput, PasscodeItemProps>(
6154
autoComplete="off"
6255
onBlur={setFalse}
6356
onFocus={setTrue}
64-
onChangeText={handleTextChange}
65-
onKeyPress={handleKeyPress}
57+
onKeyPress={handleKeyPress} // 键盘按下事件, 只用来处理键盘按下删除键的场景
58+
onChangeText={handleChangeText} // 输入框内容改变事件, 用来处理输入框内容改变的场景
6659
selectionColor={theme.colors.primary200}
6760
style={[styles.input, inputStyle]}
6861
textContentType={isOTPSupported ? 'oneTimeCode' : 'none'}
@@ -73,6 +66,7 @@ const PasscodeItem = forwardRef<TextInput, PasscodeItemProps>(
7366
ios: selectTextOnFocus,
7467
android: true,
7568
})}
69+
value={inputValue}
7670
{...rest}
7771
/>
7872
</Box>

packages/react-native/src/passcode/index.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const Passcode = forwardRef<PasscodeRef, PasscodeProps>(
2828
},
2929
ref
3030
) => {
31-
const { otpCode, inputs, handleKeyPress, handleTextChange } = usePasscode({
31+
const { otpCode, inputs, handleKeyPress, handleChangeText } = usePasscode({
3232
onChange,
3333
value,
3434
count,
@@ -56,7 +56,7 @@ const Passcode = forwardRef<PasscodeRef, PasscodeProps>(
5656
clearTextOnFocus={clearTextOnFocus}
5757
focusStyle={focusStyle}
5858
handleKeyPress={handleKeyPress(index)}
59-
handleTextChange={handleTextChange(index)}
59+
handleChangeText={handleChangeText(index)}
6060
inputContainerStyle={inputContainerStyle}
6161
inputStyle={inputStyle}
6262
inputValue={inputValue}

packages/react-native/src/passcode/reducer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export default (state: ReducerState, { type, payload }: Actions) => {
5252
return {
5353
...state,
5454
otpCode,
55+
index: (payload as SetOtpTextForIndexPayload).index,
5556
};
5657
}
5758

packages/react-native/src/passcode/type.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export interface PasscodeProps extends Omit<TextInputProps, 'onChange' | 'onChan
2626
/** 验证码长度 */
2727
count?: number;
2828
/** 验证码输入完成后的回调 */
29-
onFinish?: () => void;
29+
onFinish?: (value: string) => void;
3030
}
3131

3232
export interface PasscodeRef {
@@ -45,10 +45,10 @@ export interface PasscodeItemProps extends TextInputProps {
4545
focusStyle?: StyleProp<ViewStyle>;
4646
/** TextInput的样式 */
4747
inputStyle?: StyleProp<TextStyle>;
48-
/** 文字改变时的回调事件 */
49-
handleTextChange: (text: string) => void;
5048
/** 输入的值 */
5149
inputValue: string;
5250
/** 按键按下的回调事件 */
5351
handleKeyPress: (keyPressEvent: NativeSyntheticEvent<TextInputKeyPressEventData>) => void;
52+
/** 输入框内容改变时的回调事件 */
53+
handleChangeText: (text: string) => void;
5454
}

packages/react-native/src/passcode/usePasscode.ts

Lines changed: 27 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { ForwardedRef, RefObject, useEffect, useImperativeHandle, useReducer, useRef } from 'react';
22
import { Keyboard, NativeSyntheticEvent, Platform, TextInput, TextInputKeyPressEventData } from 'react-native';
33

4-
import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks';
4+
import { useMemoizedFn } from '@td-design/rn-hooks';
55

66
import { fillOtpCode } from './helpers';
77
import reducer from './reducer';
@@ -19,7 +19,6 @@ export default function usePasscode({
1919
}) {
2020
const previousCopiedText = useRef<string>('');
2121
const inputs = useRef<Array<RefObject<TextInput>>>([]);
22-
const [index, setIndex] = useSafeState(0);
2322

2423
const [{ otpCode, hasKeySupport }, dispatch] = useReducer(reducer, {
2524
otpCode: fillOtpCode(count, value),
@@ -36,13 +35,6 @@ export default function usePasscode({
3635
}
3736
}, [value, count]);
3837

39-
const fillInputs = useMemoizedFn((code: string) => {
40-
dispatch({
41-
type: 'setOtpCode',
42-
payload: { count, code },
43-
});
44-
});
45-
4638
useImperativeHandle(ref, () => ({
4739
reset: () => {
4840
dispatch({ type: 'clearOtp', payload: count });
@@ -75,65 +67,58 @@ export default function usePasscode({
7567
text: '',
7668
},
7769
});
78-
focusInput(inputIndex - 1);
70+
};
71+
72+
const handleChangeText = (index: number) => (text: string) => {
73+
handleInputTextChange(text, index);
7974
};
8075

8176
const handleKeyPress =
8277
(index: number) =>
8378
({ nativeEvent: { key } }: NativeSyntheticEvent<TextInputKeyPressEventData>) => {
84-
const text = key === 'Backspace' || key.length > 1 ? '' : key;
85-
handleInputTextChange(text, index);
86-
87-
if (Platform.OS === 'android' && !hasKeySupport && !isNaN(parseInt(key)))
79+
if (Platform.OS === 'android' && !hasKeySupport && !isNaN(parseInt(key))) {
8880
dispatch({ type: 'setHasKeySupport', payload: true });
81+
}
82+
83+
if (key === 'Backspace') {
84+
// 当前输入框的值
85+
const value = otpCode[`${index}`];
86+
// 清除当前输入框的值
87+
handleClearInput(index);
88+
// 如果当前输入框的值为空,则聚焦上一个输入框
89+
if (!value) {
90+
focusInput(index - 1);
91+
}
92+
}
8993
};
9094

91-
const handleTextChange = (index: number) => (text: string) => {
92-
if (
93-
(Platform.OS === 'android' && !hasKeySupport) ||
94-
// Pasted from input accessory
95-
(Platform.OS === 'ios' && text.length > 1)
96-
) {
97-
handleInputTextChange(text, index);
98-
}
99-
};
100-
10195
const handleInputTextChange = (text: string, index: number): void => {
102-
setIndex(index);
103-
104-
if (!text.length) {
105-
handleClearInput(index);
106-
}
107-
108-
if (text.length > 1) {
109-
handleClearInput(index);
110-
Keyboard.dismiss();
111-
return fillInputs(text);
112-
}
113-
114-
if (text) {
96+
if ([1, 2, 3, 4, 5, 6, 7, 8, 9, 0].includes(parseInt(text))) {
11597
dispatch({
11698
type: 'setOtpTextForIndex',
11799
payload: {
118100
text,
119101
index,
120102
},
121103
});
104+
focusInput(index + 1);
105+
} else {
106+
handleClearInput(index);
122107
}
123-
focusInput(index + 1);
124108
};
125109

126110
useEffect(() => {
127-
if (index === count - 1) {
128-
onFinish?.();
111+
const value = Object.values(otpCode).join('');
112+
if (value.length === count) {
113+
onFinish?.(value);
129114
Keyboard.dismiss();
130115
}
131-
}, [index, count]);
116+
}, [count, otpCode]);
132117

133118
return {
134119
otpCode,
135120
inputs,
136121
handleKeyPress: useMemoizedFn(handleKeyPress),
137-
handleTextChange: useMemoizedFn(handleTextChange),
122+
handleChangeText: useMemoizedFn(handleChangeText),
138123
};
139124
}

packages/react-native/src/toast/useToast.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { useEffect, useRef, useState } from 'react';
2+
import { BackHandler } from 'react-native';
23

34
import { useMemoizedFn } from '@td-design/rn-hooks';
45

@@ -18,8 +19,11 @@ export default function useToast() {
1819
clearTimeout(timer.current);
1920
};
2021

22+
/** 每次显示前,先隐藏之前的Toast */
2123
const show = (params: ToastProps) => {
22-
if (visible) return;
24+
if (visible) {
25+
hide();
26+
}
2327

2428
setOptions(params);
2529
setVisible(true);
@@ -39,6 +43,15 @@ export default function useToast() {
3943
return () => clearTimeout(timer.current);
4044
}, [visible, options]);
4145

46+
/** 当Toast显示的时候,不允许安卓物理返回键可用 */
47+
useEffect(() => {
48+
BackHandler.addEventListener('hardwareBackPress', () => visible);
49+
50+
return () => {
51+
BackHandler.removeEventListener('hardwareBackPress', () => false);
52+
};
53+
}, [visible]);
54+
4255
return {
4356
visible,
4457
options,

0 commit comments

Comments
 (0)