Skip to content

Commit 8506e55

Browse files
authored
refactor(Input): class component to function component (#427)
* test: add ActionBar component test * refactor(Input): class component to function component * fix: 处理冲突
1 parent 7bfa7c4 commit 8506e55

File tree

4 files changed

+118
-19732
lines changed

4 files changed

+118
-19732
lines changed

packages/core/src/Input/index.tsx

Lines changed: 104 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useEffect, useState } from 'react';
22
import {
33
TextInput,
44
TextInputProps,
@@ -52,123 +52,122 @@ interface InputState {
5252
value?: string;
5353
control: 'props' | 'state';
5454
}
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');
6586
}
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');
7193
}
72-
return {
73-
value: props.value,
74-
control: 'props',
75-
};
7694
}
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) => {
80101
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);
83104
}
84-
if (typeof this.props.rule === 'function') {
85-
flag = this.props.rule(value);
105+
if (typeof rule === 'function') {
106+
flag = rule(value);
86107
}
87108
if (flag) {
88-
this.setState({ value, control: 'state' });
89-
this.props.onChangeText?.(value);
109+
setDefaultValue(value);
110+
setControl('state');
111+
onChangeText?.(value);
90112
return false;
91113
}
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?.();
95118
};
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?.('');
100125
}
101-
this.props.onFocus?.(e);
126+
onFocus && onFocus(e);
102127
};
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" />)}
168155
</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;
172171

173172
const inputStyles = StyleSheet.create({
174173
container: {

test-ci/src/__tests__/actionBar.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ it('ActionBar', () => {
2626
const component = renderer.create(
2727
<ActionBar scroll keepAbsoulte useSafeArea focusIndex={1} height={48} backgroundColor="red" actions={actions} />,
2828
);
29-
3029
expect(component.root.props.scroll).toBeTruthy();
3130
expect(component.root.props.keepAbsoulte).toBeTruthy();
3231
expect(component.root.props.useSafeArea).toBeTruthy();

test-ci/src/__tests__/input.tsx

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import 'react-native';
2+
import React from 'react';
3+
import Input from '../lib/Input';
4+
import { render, fireEvent } from '@testing-library/react-native';
5+
6+
describe('input', () => {
7+
it('snapshot', () => {
8+
const DefaultInput = () => {
9+
return <Input testID="input" />;
10+
};
11+
// const { toJSON } = render(<DefaultInput />);
12+
// expect(toJSON()).toMatchSnapshot();
13+
});
14+
});

0 commit comments

Comments
 (0)