Skip to content

Commit 11fad95

Browse files
fix: TextField defaultValue change (#2388)
* fix: TextField defaultValue change * fix test * update webDemo to demonstrate text field default value * code review + add tests * Update webDemo/package.json Co-authored-by: Lidor Dafna <[email protected]> * fix demo & and tests * fix lint Co-authored-by: Lidor Dafna <[email protected]> Co-authored-by: Lidor Dafna <[email protected]>
1 parent ab3127a commit 11fad95

File tree

6 files changed

+87
-19
lines changed

6 files changed

+87
-19
lines changed

src/incubator/TextField/__tests__/index.spec.js

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React, {useState} from 'react';
22
import {fireEvent, render} from '@testing-library/react-native';
33
import TextField from '../index';
4+
import {Constants} from '../../../commons/new';
45

56
const defaultProps = {
67
testID: 'field',
@@ -29,7 +30,7 @@ describe('TextField', () => {
2930

3031
const input = renderTree.getByTestId('field');
3132
renderTree.getByPlaceholderText(defaultProps.placeholder);
32-
33+
3334
fireEvent(input, 'focus');
3435
renderTree.getByPlaceholderText(defaultProps.placeholder);
3536
});
@@ -83,4 +84,37 @@ describe('TextField', () => {
8384
expect(validationMessageElement).toBe(null);
8485
});
8586
});
87+
88+
describe('defaultValue', () => {
89+
const props = {
90+
...defaultProps,
91+
defaultValue: 'someDefaultValue',
92+
value: 'someValue'
93+
};
94+
95+
it('value should equal defaultValue on first render when value not given', () => {
96+
const renderTree = render(<TestCase {...props} value={undefined}/>);
97+
98+
renderTree.getByDisplayValue('someDefaultValue');
99+
});
100+
101+
it('value should equal value on first render when given', () => {
102+
const renderTree = render(<TestCase {...props} defaultValue={undefined}/>);
103+
104+
renderTree.getByDisplayValue('someValue');
105+
});
106+
107+
it.each`
108+
platform | isWeb
109+
${'web'} | ${true}
110+
${'native'} | ${false}
111+
`('on $platform should reset defaultValue when prop changed after first render', (args) => {
112+
Constants.isWeb = args.isWeb;
113+
114+
const renderTree = render(<TestCase {...props} value={undefined}/>);
115+
116+
renderTree.rerender(<TestCase {...props} value={undefined} defaultValue={'someUpdatedDefaultValue'}/>);
117+
renderTree.getByDisplayValue('someUpdatedDefaultValue');
118+
});
119+
});
86120
});

src/incubator/TextField/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ const TextField = (props: InternalTextFieldProps) => {
167167
onChangeText={onChangeText}
168168
placeholder={placeholder}
169169
hint={hint}
170+
value={fieldState.value}
170171
/>
171172
</View>
172173
)}

src/incubator/TextField/useFieldState.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import _ from 'lodash';
33
import * as Presenter from './Presenter';
44
import {useDidUpdate} from 'hooks';
55
import {FieldStateProps} from './types';
6+
import {Constants} from '../../commons/new';
67

78
export default function useFieldState({
89
validate,
@@ -13,11 +14,24 @@ export default function useFieldState({
1314
onChangeValidity,
1415
...props
1516
}: FieldStateProps) {
16-
const [value, setValue] = useState(props.value);
17+
const [value, setValue] = useState(props.value ?? props.defaultValue);
1718
const [isFocused, setIsFocused] = useState(false);
1819
const [isValid, setIsValid] = useState<boolean | undefined>(undefined);
1920
const [failingValidatorIndex, setFailingValidatorIndex] = useState<number | undefined>(undefined);
2021

22+
useEffect(() => {
23+
if (Constants.isWeb && !props.value && props.defaultValue && props.defaultValue !== value) {
24+
setValue(props.defaultValue);
25+
26+
if (validateOnChange) {
27+
validateField(props.defaultValue);
28+
}
29+
}
30+
31+
/* On purpose listen only to props.defaultValue change */
32+
/* eslint-disable-next-line react-hooks/exhaustive-deps*/
33+
}, [props.defaultValue, validateOnChange]);
34+
2135
useEffect(() => {
2236
if (validateOnStart) {
2337
validateField();

webDemo/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"react-native-shimmer-placeholder": "^2.0.8",
2929
"react-native-svg": "^12.1.0",
3030
"react-native-svg-transformer": "^0.14.3",
31-
"react-native-ui-lib": "6.21.2-snapshot.1927",
31+
"react-native-ui-lib": "snapshot",
3232
"react-native-web": "^0.18.6",
3333
"typescript": "^4.4.2"
3434
},

webDemo/src/App.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {useState, useRef} from 'react';
22
import {StyleSheet, ScrollView, ActivityIndicator, Animated} from 'react-native';
33

4-
import TextField from 'react-native-ui-lib/TextField';
4+
// import TextField from 'react-native-ui-lib/TextField';
55
import View from 'react-native-ui-lib/View';
66
import Button from 'react-native-ui-lib/Button';
77
import Switch from 'react-native-ui-lib/Switch';
@@ -18,7 +18,14 @@ import AnimatedImage from 'react-native-ui-lib/AnimatedImage';
1818
import Avatar from 'react-native-ui-lib/Avatar';
1919
import Drawer from 'react-native-ui-lib/Drawer';
2020

21-
import {Colors, Spacings, Typography, Assets, Text} from 'react-native-ui-lib';
21+
import {
22+
Colors,
23+
Spacings,
24+
Typography,
25+
Assets,
26+
Text,
27+
Incubator
28+
} from 'react-native-ui-lib';
2229

2330
import Picker from './examples/Picker';
2431
import RadioGroup from './examples/RadioButtonGroup';
@@ -152,24 +159,36 @@ const itemsToRender: ItemToRender[] = [
152159
},
153160
{
154161
title: 'TextField',
155-
FC: () => (
156-
<TextField
157-
text70
158-
migrate
159-
containerStyle={{marginBottom: 10}}
160-
placeholder="type here..."
161-
onChangeText={(text: string) => {
162-
console.log(text);
163-
}}
164-
/>)
162+
FC: () => {
163+
const [defaultValue, setDefaultValue] = useState('I am Default value');
164+
const updateDefaultValue = () => {
165+
setDefaultValue(`${defaultValue}1`);
166+
};
167+
168+
return (
169+
<>
170+
<Button label="update default value" onPress={updateDefaultValue}/>
171+
<Incubator.TextField
172+
text70
173+
migrate
174+
defaultValue={defaultValue}
175+
containerStyle={{marginBottom: 10}}
176+
placeholder="type here..."
177+
onChangeText={(text: string) => {
178+
console.log(text);
179+
}}
180+
/>
181+
</>
182+
);
183+
}
165184
},
166185
{
167186
title: 'Switch',
168187
FC: () => {
169188
const [switchValue, setSwitchValue] = useState(true);
170189
return (
171190
<Switch
172-
191+
173192
value={switchValue}
174193
onValueChange={setSwitchValue}
175194
style={{marginBottom: 20}}

webDemo/webpack.config.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,15 +46,15 @@ const imageLoaderConfiguration = {
4646
esModule: false
4747
}
4848
}
49-
};
49+
};
5050

5151
const babelLoaderAppConfiguration = {
5252
test: /\.(js|jsx|ts|tsx)$/,
5353
include: baseProjectSource,
5454
use: useBabelForRN
5555
};
5656

57-
module.exports =
57+
module.exports =
5858
{
5959
entry: {
6060
app: path.resolve(appDirectory, './src/index.ts')
@@ -84,7 +84,7 @@ module.exports =
8484
devServer: {
8585
contentBase: path.resolve(appDirectory, './dist'),
8686
compress: true,
87-
port: 9002
87+
port: 9001
8888
},
8989
plugins: [
9090
new CleanWebpackPlugin({

0 commit comments

Comments
 (0)