У меня в приложении два типа ввода текста. Поисковый ввод и другие текстовые вводы (для форм, комментариев ...), которые могут иметь значок.
Поисковый ввод получает onSubmit (для клавиатуры), который также используется в сенсорной непрозрачности его значок. Другие текстовые поля ввода не имеют свойства onSubmit, но их значки могут иметь функцию onPress.
Я никогда не реализовывал фабричный шаблон в React, могу ли я его использовать? Если нет, следует ли обобщить компонент ввода текста? Или два компонента - это нормально?
Что вы думаете?
Поисковый ввод:
import React, { useState } from "react";
import { View, TouchableOpacity, Keyboard, StyleSheet } from "react-native";
import { TextInput, useTheme } from "react-native-paper";
import { Icon } from "react-native-elements";
import PropTypes from "prop-types";
export default function SearchInput(props) {
const { colors } = useTheme();
let { placeholder, maxLength, color, onSearch } = props;
const [text, setText] = useState("");
if (!color) {
color = colors.white;
}
const handleChangeText = (text) => {
setText(text);
};
const handleSubmit = () => {
onSearch(text);
// Close the keyboard
Keyboard.dismiss();
};
return (
<>
<View style={styles.inputContainer}>
<TextInput
placeholder={placeholder}
value={text}
maxLength={maxLength}
dense
autoCorrect={false}
autoCapitalize="none"
selectionColor={colors.primary}
onChangeText={handleChangeText}
onSubmitEditing={handleSubmit}
style={[styles.input, { backgroundColor: color }]}
/>
<View pointerEvents="box-none" style={styles.iconContainer}>
<TouchableOpacity activeOpacity={0.5} onPress={handleSubmit}>
<Icon name="search" type="material" color={colors.gray} size={20} />
</TouchableOpacity>
</View>
</View>
</>
);
}
SearchInput.propTypes = {
placeholder: PropTypes.string,
maxLength: PropTypes.number,
color: PropTypes.string,
onSearch: PropTypes.func.isRequired,
};
SearchInput.defaultProps = {
maxLength: 30,
};
const styles = StyleSheet.create({
inputContainer: {
width: "100%",
},
input: {
paddingRight: 5,
fontSize: 14,
padding: 5,
},
iconContainer: {
...StyleSheet.absoluteFillObject,
justifyContent: "center",
alignItems: "flex-end",
marginRight: 5,
},
});
Другой текстовый ввод:
import React, { useState, forwardRef } from "react";
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
import { TextInput as RNPTextInput, useTheme } from "react-native-paper";
import { Icon } from "react-native-elements";
import PropTypes from "prop-types";
const TextInput = forwardRef((props, ref) => {
const { colors } = useTheme();
let {
placeholder,
multiline,
maxLength,
color,
icon,
counter,
onSubmit,
} = props;
const [text, setText] = useState("");
if (!color) {
color = colors.white;
}
// Default props for optional nested object
if (icon) {
if (!icon.color) {
icon.color = colors.gray;
}
if (!icon.size) {
icon.size = 20;
}
if (!icon.onPress) {
icon.onPress = () => {};
}
}
const handleChangeText = (text) => {
setText(text);
};
const handleIconPress = () => {
const { onPress } = icon;
onPress();
};
const handleSubmit = () => {
onSubmit(text);
};
return (
<>
<View style={styles.inputContainer}>
<RNPTextInput
ref={ref}
placeholder={placeholder}
value={text}
multiline={multiline}
maxLength={maxLength}
maxHeight={85}
dense
autoCorrect={false}
autoCapitalize="none"
selectionColor={colors.primary}
onChangeText={handleChangeText}
style={[styles.input, { backgroundColor: color }]}
onSubmitEditing={handleSubmit}
/>
{icon && (
<View pointerEvents="box-none" style={styles.iconContainer}>
<TouchableOpacity activeOpacity={0.5} onPress={handleIconPress}>
<Icon
name={icon.name}
type={icon.type}
color={icon.color}
size={icon.size}
/>
</TouchableOpacity>
</View>
)}
</View>
{counter && (
<View style={styles.charactersCounterContainer}>
<Text style={[styles.charactersCounter, { color: colors.gray }]}>
{`${text.length}/${maxLength}`}
</Text>
</View>
)}
</>
);
});
TextInput.propTypes = {
placeholder: PropTypes.string,
multiline: PropTypes.bool,
maxLength: PropTypes.number,
color: PropTypes.string,
icon: PropTypes.shape({
name: PropTypes.string.isRequired,
type: PropTypes.string.isRequired,
color: PropTypes.string,
size: PropTypes.number,
onPress: PropTypes.func,
}),
counter: PropTypes.bool,
onSubmit: PropTypes.func,
};
TextInput.defaultProps = {
placeholder: null,
multiline: false,
maxLength: 300,
icon: null,
counter: false,
onSubmit: () => {},
};
export default TextInput;
const styles = StyleSheet.create({
inputContainer: {
width: "100%",
},
input: {
paddingRight: 5,
fontSize: 14,
padding: 5,
},
iconContainer: {
...StyleSheet.absoluteFillObject,
justifyContent: "center",
alignItems: "flex-end",
marginRight: 5,
},
charactersCounterContainer: {
marginTop: 5,
width: "100%",
},
charactersCounter: {
textAlign: "right",
fontSize: 12,
},
});