|
1 | | -import React from 'react'; |
| 1 | +import React, { useEffect, useState } from 'react'; |
2 | 2 | import { |
3 | 3 | TextInput, |
4 | 4 | TextInputProps, |
@@ -52,123 +52,122 @@ interface InputState { |
52 | 52 | value?: string; |
53 | 53 | control: 'props' | 'state'; |
54 | 54 | } |
55 | | -export default class Input extends React.Component<InputProps, InputState> { |
56 | | - state: InputState = { |
57 | | - value: this.props.value, |
58 | | - control: 'state', |
59 | | - }; |
60 | | - static getDerivedStateFromProps(props: InputProps, state: InputState) { |
61 | | - if (state.control === 'state' && props.value === state.value) { |
62 | | - return { |
63 | | - control: 'props', |
64 | | - }; |
| 55 | + |
| 56 | +const Input = (props: InputProps) => { |
| 57 | + const { |
| 58 | + wrongfulHandle, |
| 59 | + rule, |
| 60 | + value, |
| 61 | + onChangeText, |
| 62 | + onFocus, |
| 63 | + clearText, |
| 64 | + disabled = false, |
| 65 | + clear, |
| 66 | + clearStyle, |
| 67 | + renderClear, |
| 68 | + extraStart, |
| 69 | + extraEnd, |
| 70 | + style = [], |
| 71 | + containerStyle, |
| 72 | + border = 'bottom', |
| 73 | + borderColor = '#ccc', |
| 74 | + error = false, |
| 75 | + renderError, |
| 76 | + inputRef, |
| 77 | + ...others |
| 78 | + } = props; |
| 79 | + |
| 80 | + const [defaultValue, setDefaultValue] = useState<string | undefined>(value); |
| 81 | + const [control, setControl] = useState<string>('state'); |
| 82 | + |
| 83 | + useEffect(() => { |
| 84 | + if (control === 'state' && value === defaultValue) { |
| 85 | + setControl('props'); |
65 | 86 | } |
66 | | - if (props.value !== state.value) { |
67 | | - if (state.control === 'state') { |
68 | | - return { |
69 | | - control: 'props', |
70 | | - }; |
| 87 | + if (value !== defaultValue) { |
| 88 | + if (control === 'state') { |
| 89 | + setControl('props'); |
| 90 | + } else { |
| 91 | + setDefaultValue(value); |
| 92 | + setControl('props'); |
71 | 93 | } |
72 | | - return { |
73 | | - value: props.value, |
74 | | - control: 'props', |
75 | | - }; |
76 | 94 | } |
77 | | - return null; |
78 | | - } |
79 | | - onChangeText = (value: string) => { |
| 95 | + }, [value, control]); |
| 96 | + |
| 97 | + const fontSize = StyleSheet.flatten(style).fontSize || 14; |
| 98 | + const minHeight = StyleSheet.flatten(containerStyle)?.height || 30; |
| 99 | + |
| 100 | + const onInputChange = (value: string) => { |
80 | 101 | let flag = true; |
81 | | - if (this.props.rule instanceof RegExp) { |
82 | | - flag = this.props.rule.test(value); |
| 102 | + if (rule instanceof RegExp) { |
| 103 | + flag = rule.test(value); |
83 | 104 | } |
84 | | - if (typeof this.props.rule === 'function') { |
85 | | - flag = this.props.rule(value); |
| 105 | + if (typeof rule === 'function') { |
| 106 | + flag = rule(value); |
86 | 107 | } |
87 | 108 | if (flag) { |
88 | | - this.setState({ value, control: 'state' }); |
89 | | - this.props.onChangeText?.(value); |
| 109 | + setDefaultValue(value); |
| 110 | + setControl('state'); |
| 111 | + onChangeText?.(value); |
90 | 112 | return false; |
91 | 113 | } |
92 | | - this.setState({ value: this.state.value || '', control: 'state' }); |
93 | | - this.props.onChangeText?.(this.state.value || ''); |
94 | | - this.props.wrongfulHandle?.(); |
| 114 | + setDefaultValue(defaultValue || ''); |
| 115 | + setControl('state'); |
| 116 | + onChangeText?.(defaultValue || ''); |
| 117 | + wrongfulHandle?.(); |
95 | 118 | }; |
96 | | - onFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => { |
97 | | - if (this.props.clearText) { |
98 | | - this.setState({ value: '', control: 'state' }); |
99 | | - this.props.onChangeText?.(''); |
| 119 | + |
| 120 | + const onInputFocus = (e: NativeSyntheticEvent<TextInputFocusEventData>) => { |
| 121 | + if (clearText) { |
| 122 | + setDefaultValue(''); |
| 123 | + setControl('state'); |
| 124 | + onChangeText?.(''); |
100 | 125 | } |
101 | | - this.props.onFocus?.(e); |
| 126 | + onFocus && onFocus(e); |
102 | 127 | }; |
103 | | - render() { |
104 | | - const { |
105 | | - wrongfulHandle, |
106 | | - rule, |
107 | | - value, |
108 | | - onChangeText, |
109 | | - clearText, |
110 | | - disabled = false, |
111 | | - clear, |
112 | | - clearStyle, |
113 | | - renderClear, |
114 | | - extraStart, |
115 | | - extraEnd, |
116 | | - style = [], |
117 | | - containerStyle, |
118 | | - border = 'bottom', |
119 | | - borderColor = '#ccc', |
120 | | - error = false, |
121 | | - renderError, |
122 | | - inputRef, |
123 | | - ...others |
124 | | - } = this.props; |
125 | | - const fontSize = StyleSheet.flatten(style).fontSize || 14; |
126 | | - const minHeight = StyleSheet.flatten(containerStyle)?.height || 30; |
127 | | - return ( |
128 | | - <View |
129 | | - style={[ |
130 | | - { |
131 | | - flexDirection: 'row', |
132 | | - backgroundColor: '#fff', |
133 | | - alignItems: 'center', |
134 | | - paddingVertical: 0, |
135 | | - height: minHeight, |
136 | | - }, |
137 | | - containerStyle, |
138 | | - ]} |
139 | | - > |
140 | | - <View style={[inputStyles.container, { flex: 1, borderColor: borderColor }, border ? inputStyles[border] : {}]}> |
141 | | - {typeof extraStart === 'string' ? ( |
142 | | - <Text style={{ color: '#888888', fontSize }}>{extraStart}</Text> |
143 | | - ) : ( |
144 | | - extraStart |
145 | | - )} |
146 | | - <TextInput |
147 | | - {...others} |
148 | | - ref={inputRef} |
149 | | - editable={!disabled} |
150 | | - value={this.state.value} |
151 | | - onChangeText={this.onChangeText} |
152 | | - onFocus={this.onFocus} |
153 | | - style={[{ fontSize }, inputStyles.input, style]} |
154 | | - /> |
155 | | - {typeof extraEnd === 'string' ? <Text style={{ color: '#888888', fontSize }}>{extraEnd}</Text> : extraEnd} |
156 | | - {error && (renderError || <Icon name="circle-close" color="#dc3545" />)} |
157 | | - </View> |
158 | | - {clear && ( |
159 | | - <TouchableOpacity |
160 | | - onPress={() => { |
161 | | - this.setState({ value: '', control: 'state' }); |
162 | | - this.props.onChangeText?.(''); |
163 | | - }} |
164 | | - > |
165 | | - {renderClear || <Text style={[{ color: '#888888', fontSize }, clearStyle]}>清除</Text>} |
166 | | - </TouchableOpacity> |
167 | | - )} |
| 128 | + |
| 129 | + return ( |
| 130 | + <View |
| 131 | + style={[ |
| 132 | + { |
| 133 | + flexDirection: 'row', |
| 134 | + backgroundColor: '#fff', |
| 135 | + alignItems: 'center', |
| 136 | + paddingVertical: 0, |
| 137 | + height: minHeight, |
| 138 | + }, |
| 139 | + containerStyle, |
| 140 | + ]} |
| 141 | + > |
| 142 | + <View style={[inputStyles.container, { flex: 1, borderColor: borderColor }, border ? inputStyles[border] : {}]}> |
| 143 | + {typeof extraStart === 'string' ? <Text style={{ color: '#888888', fontSize }}>{extraStart}</Text> : extraStart} |
| 144 | + <TextInput |
| 145 | + {...others} |
| 146 | + ref={inputRef} |
| 147 | + editable={!disabled} |
| 148 | + value={defaultValue} |
| 149 | + onChangeText={onInputChange} |
| 150 | + onFocus={onInputFocus} |
| 151 | + style={[{ fontSize }, inputStyles.input, style]} |
| 152 | + /> |
| 153 | + {typeof extraEnd === 'string' ? <Text style={{ color: '#888888', fontSize }}>{extraEnd}</Text> : extraEnd} |
| 154 | + {error && (renderError || <Icon name="circle-close" color="#dc3545" />)} |
168 | 155 | </View> |
169 | | - ); |
170 | | - } |
171 | | -} |
| 156 | + {clear && ( |
| 157 | + <TouchableOpacity |
| 158 | + onPress={() => { |
| 159 | + setDefaultValue(''); |
| 160 | + setControl('state'); |
| 161 | + onInputChange?.(''); |
| 162 | + }} |
| 163 | + > |
| 164 | + {renderClear || <Text style={[{ color: '#888888', fontSize }, clearStyle]}>清除</Text>} |
| 165 | + </TouchableOpacity> |
| 166 | + )} |
| 167 | + </View> |
| 168 | + ); |
| 169 | +}; |
| 170 | +export default Input; |
172 | 171 |
|
173 | 172 | const inputStyles = StyleSheet.create({ |
174 | 173 | container: { |
|
0 commit comments