javascript - React 原生工厂模式
问题描述
我的应用程序中有两种文本输入类型。搜索输入和其他可以有图标的文本输入(用于表单、评论...)。
搜索输入接收一个 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,
},
});
解决方案
推荐阅读
- arrays - 我该如何修复这个数组?
- php - 具有动态类型的 Laravel 模型字段
- servlets - Websphere Application Server 9 中 Servlet uri 末尾的斜杠抛出 404,但在 WAS 7 中运行良好
- javascript - 在 JavaScript 中使用正则表达式自动完成最后一个不完整的短语
- android - Android 上的 ARCore 替代方案
- docker - 使用 Symfony 5 配置的 Docker
- r - 使用 rm_between 提取复杂句子
- keras - ValueError: 形状为 (32, 5) 的目标数组被传递给形状 (None, 4) 的输出,同时用作损失 categorical_crossentropy
- java - 如何使用 MediaPlayer 播放存储在资产中找到的文件夹中的音乐
- pentaho - Pentaho - 根据输入字段生成 UUID