Skip to content
This repository was archived by the owner on Apr 6, 2023. It is now read-only.

Commit af7d1bf

Browse files
docs: Add react native input mask example
docs: Add react native input mask example
1 parent f403915 commit af7d1bf

3 files changed

Lines changed: 162 additions & 73 deletions

File tree

docs/src/docs/examples/react-native-input-mask.mdx

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -9,42 +9,36 @@ description: Learn how to use React Native Input Mask with Unform
99

1010
Create a base Input component, as described in the [React Native](/guides/react-native) example.
1111

12-
Here is a small difference: assuming that the data to be sent in the form should not be formatted, we will use a `rawValue` property that will inform us of the component's gross value.
12+
Here is a small difference: assuming that the data to be sent in the form should not be formatted, we will use a `rawText` property that will inform us of the component's gross value.
1313

14-
Note that `getValue` can return the `rawValue` property, that is, if the form does not use an `InputMask`, the returned value will be the one stored in `inputRef`
14+
Note that `getValue` can return the `rawText` property, that is, if the form does not use an `InputMask`, the returned value will be the one stored in `inputRef`
1515

1616
```jsx lineNumbers=true
1717
import React, { useRef, useEffect, useCallback } from 'react';
1818
import { TextInput } from 'react-native';
1919
import { useField } from '@unform/core';
2020

21-
function Input({ name, onChangeText, rawValue, ...rest }) {
22-
// add handleOnChange
23-
const handleOnChange = useCallback(
24-
text => {
25-
if (inputRef.current) inputRef.current.value = text;
26-
27-
if (onChangeText) onChangeText(text);
28-
},
29-
[onChangeText],
30-
);
21+
function Input({ name, label, onChangeText, rawText, onInitialData, ...rest }) {
22+
// this will cause the InputMask to be updated if the Form receives initial data
23+
useEffect(() => {
24+
if (onInitialData) onInitialData(defaultValue);
25+
}, [defaultValue, onInitialData]);
3126

3227
useEffect(() => {
3328
registerField({
3429
// modify getValue
35-
getValue(ref) {
36-
return rawValue || ref.value;
30+
getValue() {
31+
if (rawText) return rawText;
32+
33+
if (inputRef.current) return inputRef.current.value;
34+
35+
return '';
3736
},
3837
});
39-
}, [fieldName, rawValue, registerField]);
38+
}, [fieldName, rawText, registerField]);
4039

4140
return (
42-
<TextInput
43-
ref={inputRef}
44-
defaultValue={defaultValue}
45-
onChangeText={handleOnChange}
46-
{...rest}
47-
/>
41+
{...}
4842
);
4943
}
5044

@@ -54,40 +48,41 @@ export default Input;
5448
## InputMask component
5549

5650
Inform which component should be rendered using the `customTextInput` property, in this case `Input`.
57-
Add `rawValue` to the `Input` properties using `customTextInputProps`
51+
Add `rawText` to the `Input` properties using `customTextInputProps`
5852

5953
```jsx lineNumbers=true
60-
import React, { useState, useCallback } from 'react';
54+
import React, { useState, useCallback, forwardRef } from 'react';
6155
import { TextInputMask } from 'react-native-masked-text';
6256

6357
import Input from '../Input';
6458

65-
const InputMask = ({ type, ...rest }) => {
66-
const [value, setValue] = useState('');
67-
const [rawValue, setRawValue] = useState('');
59+
const InputMask = ({ type, ...rest }, inputRef) => {
60+
const [text, setText] = useState('');
61+
const [rawText, setRawText] = useState('');
6862

69-
const handleOnChangeText = useCallback((maskedValue, unmaskedValue) => {
70-
setValue(maskedValue);
71-
setRawValue(unmaskedValue);
63+
const handleChangeText = useCallback((maskedText, unmaskedText) => {
64+
setText(maskedText);
65+
setRawText(unmaskedText);
7266
}, []);
7367

7468
return (
7569
<TextInputMask
7670
type={type}
7771
includeRawValueInChangeText
78-
value={value}
79-
onChangeText={handleOnChangeText}
72+
value={text}
73+
onChangeText={handleChangeText}
8074
customTextInput={Input}
8175
customTextInputProps={{
82-
rawValue,
83-
...rest,
76+
ref: inputRef,
77+
rawText,
78+
onInitialData: setText,
8479
}}
8580
{...rest}
8681
/>
8782
);
8883
};
8984

90-
export default InputMask;
85+
export default forwardRef(InputMask);
9186
```
9287

9388
## Example
@@ -107,8 +102,8 @@ const App = () => {
107102
return (
108103
<View style={{ flex: 1, justifyContent: 'center', alignContent: 'center' }}>
109104
<Form ref={formRef} onSubmit={handleSubmit}>
110-
<Input name="first_name" />
111-
<InputMask type="cpf" name="cpf" keyboardType="numeric" />
105+
<Input name="first_name" label="Name" />
106+
<InputMask type="cpf" name="cpf" keyboardType="numeric" label="CPF" />
112107
<Button
113108
onPress={() => formRef.current.submitForm()}
114109
title="console.log"

docs/src/docs/guides/react-native.mdx

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ The Unform API is almost identic between web and mobile, below you can see an ex
99

1010
In React Native we need to use `TextInput` provided by the `react-native` package.
1111

12-
Also, to keep the field uncontrolled, that is, don't store it's value within a state, we need to track input changes and save its value inside the input reference.
12+
Also, to keep the field uncontrolled, that is, don't store it's value within a state, we need to use references's `value` to store the field value and use the `setNativeProps` to set the value within native renderer.
1313

1414
```jsx title=Input.js lineNumbers=true
15-
import React, { useEffect, useRef, useState } from 'react';
16-
17-
import { TextInput } from 'react-native';
15+
import React, { useRef, useEffect, useCallback } from 'react';
16+
import { Text, TextInput } from 'react-native';
1817
import { useField } from '@unform/core';
1918

20-
function Input({ name, ...rest }) {
19+
function Input({ name, label, onChangeText, ...rest }) {
2120
const inputRef = useRef(null);
2221

2322
const { fieldName, registerField, defaultValue, error } = useField(name);
@@ -26,38 +25,54 @@ function Input({ name, ...rest }) {
2625
inputRef.current.value = defaultValue;
2726
}, [defaultValue]);
2827

28+
useEffect(() => {
29+
if (inputRef.current) inputRef.current.value = defaultValue;
30+
}, [defaultValue]);
31+
2932
useEffect(() => {
3033
registerField({
3134
name: fieldName,
3235
ref: inputRef.current,
33-
path: 'value',
34-
clearValue(ref) {
35-
ref.value = '';
36-
ref.clear();
36+
getValue() {
37+
if (inputRef.current) return inputRef.current.value;
38+
39+
return '';
3740
},
3841
setValue(ref, value) {
39-
ref.setNativeProps({ text: value });
40-
inputRef.current.value = value;
42+
if (inputRef.current) {
43+
inputRef.current.setNativeProps({ text: value });
44+
inputRef.current.value = value;
45+
}
4146
},
42-
getValue(ref) {
43-
return ref.value;
47+
clearValue() {
48+
if (inputRef.current) {
49+
inputRef.current.setNativeProps({ text: '' });
50+
inputRef.current.value = '';
51+
}
4452
},
4553
});
4654
}, [fieldName, registerField]);
4755

56+
const handleChangeText = useCallback(
57+
text => {
58+
if (inputRef.current) inputRef.current.value = text;
59+
60+
if (onChangeText) onChangeText(text);
61+
},
62+
[onChangeText],
63+
);
64+
4865
return (
49-
<TextInput
50-
ref={inputRef}
51-
keyboardAppearance="dark"
52-
defaultValue={defaultValue}
53-
placeholderTextColor="#666360"
54-
onChangeText={value => {
55-
if (inputRef.current) {
56-
inputRef.current.value = value;
57-
}
58-
}}
59-
{...rest}
60-
/>
66+
<>
67+
{label && <Text>{label}</Text>}
68+
69+
<TextInput
70+
ref={inputRef}
71+
onChangeText={handleChangeText}
72+
defaultValue={defaultValue}
73+
{...rest}
74+
/>
75+
</>
6176
);
6277
}
6378

docs/src/docs/recipes/typescript.mdx

Lines changed: 91 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,26 +43,20 @@ const MyForm: React.FC = () => {
4343
export default MyForm;
4444
```
4545

46-
## Simple input
46+
## Simple input (ReactJS)
4747

4848
When creating a simple HTML input or any other HTML element used for input source, remember to always extend the element props. In web you can always use the `JSX.IntrinsicElements['element']` to get the props adapted to JSX.
4949

50-
In React Native you can import default component props directly from `react-native` package, for example:
51-
52-
```jsx
53-
import { TextInputProps } from 'react-native';
54-
```
55-
5650
Also, in web (ReactJS) remember to reference the global element inside `useRef` hook and **always** set the default value to `null`.
5751

58-
```jsx lineNumbers
52+
```tsx lineNumbers=true
5953
import React, { useEffect, useRef } from 'react';
6054
import { useField } from '@unform/core';
6155

6256
interface Props {
6357
name: string;
6458
label?: string;
65-
};
59+
}
6660

6761
type InputProps = JSX.IntrinsicElements['input'] & Props;
6862

@@ -76,12 +70,12 @@ const Input: React.FC<InputProps> = ({ name, label, ...rest }) => {
7670
name: fieldName,
7771
path: 'value',
7872
ref: inputRef.current,
79-
})
73+
});
8074
}, [fieldName, registerField]);
8175

8276
return (
8377
<>
84-
{ label && <label htmlFor={fieldName}>{label}</label> }
78+
{label && <label htmlFor={fieldName}>{label}</label>}
8579

8680
<input
8781
id={fieldName}
@@ -90,7 +84,92 @@ const Input: React.FC<InputProps> = ({ name, label, ...rest }) => {
9084
{...rest}
9185
/>
9286

93-
{ error && <span>{error}</span> }
87+
{error && <span>{error}</span>}
88+
</>
89+
);
90+
};
91+
92+
export default Input;
93+
```
94+
95+
## Simple input (React Native)
96+
97+
Let's create an `InputProps` interface for the component.
98+
In addition, we will create an `InputReference` interface to use on the useRef hook.
99+
100+
We can also tell `registerField` what kind of value this Entry will store
101+
102+
```tsx lineNumbers=true
103+
import React, { useRef, useEffect, useCallback } from 'react';
104+
import { TextInput, TextInputProps, Text } from 'react-native';
105+
import { useField } from '@unform/core';
106+
107+
interface InputProps extends TextInputProps {
108+
name: string;
109+
label: string;
110+
}
111+
112+
interface InputReference extends TextInput {
113+
value: string;
114+
}
115+
116+
const Input: React.FC<InputProps> = ({
117+
name,
118+
label,
119+
onChangeText,
120+
...rest
121+
}) => {
122+
const inputRef = useRef<InputReference>(null);
123+
124+
const { fieldName, registerField, defaultValue = '', error } = useField(name);
125+
126+
useEffect(() => {
127+
if (inputRef.current) inputRef.current.value = defaultValue;
128+
}, [defaultValue]);
129+
130+
useEffect(() => {
131+
registerField<string>({
132+
name: fieldName,
133+
ref: inputRef.current,
134+
getValue() {
135+
if (inputRef.current) return inputRef.current.value;
136+
137+
return '';
138+
},
139+
setValue(ref, value) {
140+
if (inputRef.current) {
141+
inputRef.current.setNativeProps({ text: value });
142+
inputRef.current.value = value;
143+
}
144+
},
145+
clearValue() {
146+
if (inputRef.current) {
147+
inputRef.current.setNativeProps({ text: '' });
148+
inputRef.current.value = '';
149+
}
150+
},
151+
});
152+
}, [fieldName, registerField]);
153+
154+
const handleChangeText = useCallback(
155+
(value: string) => {
156+
if (inputRef.current) inputRef.current.value = value;
157+
158+
if (onChangeText) onChangeText(value);
159+
},
160+
[onChangeText],
161+
);
162+
163+
return (
164+
<>
165+
{label && <Text>{label}</Text>}
166+
167+
<TextInput
168+
ref={inputRef}
169+
onChangeText={handleChangeText}
170+
defaultValue={defaultValue}
171+
{...rest}
172+
/>
94173
</>
95174
);
96175
};

0 commit comments

Comments
 (0)