[英]React Native Siri Dictation cut short by rerenders - Functional Component
我有一個反應原生項目。
我有一個輸入,我在應用程序的幾個地方使用。 我可以輸入它沒問題,但我使用 ios 鍵盤的 siri 聽寫,單詞被重新渲染縮短了。
之前有人問過類似的問題, React native dictation 在 iOS 上突然斷詞,但唯一的答案是 class 組件。 有沒有辦法用功能組件解決這個問題?
我嘗試在 textChangeHandler 周圍拋出一個 useMemo(),通過阻止所有 state 更新,這確實允許 siri 工作。 但這不好,因為那時我沒有數據。
這是我的組件:
import React, { useReducer, useEffect, useRef } from 'react';
import {
StyleSheet,
View,
Text,
TextInput,
TouchableOpacity,
} from 'react-native';
import mergeRefs from 'react-merge-refs';
import PropTypes from 'prop-types';
const INPUT_CHANGE = 'INPUT_CHANGE';
const INPUT_BLUR = 'INPUT_BLUR';
const formatDate = date => {
const options = {
month: 'numeric',
day: 'numeric',
year: '2-digit',
};
const formattedDate = new Date(date);
const _formattedDate = formattedDate.toLocaleDateString('en-US', options);
return _formattedDate;
};
const inputReducer = (state, action) => {
switch (action.type) {
case INPUT_CHANGE:
return {
...state,
value: action.value,
isValid: action.isValid,
};
case INPUT_BLUR:
return {
...state,
touched: true,
};
default:
return state;
}
};
const Input = React.forwardRef((props, ref) => {
const [inputState, dispatch] = useReducer(inputReducer, {
value: props.initialValue ? props.initialValue : '',
isValid: props.initiallyValid ? props.initiallyValid : true,
touched: props.initialValue ? true : false,
});
const { onInputChange, id } = props;
useEffect(() => {
onInputChange(id, inputState.value, inputState.isValid);
}, [inputState, onInputChange, id]);
const textChangeHandler = text => {
const emailRegex =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
let isValid = true;
if (props.required && text.trim().length === 0) {
isValid = false;
}
if (props.email && !emailRegex.test(text.toLowerCase())) {
isValid = false;
}
if (props.min != null && +text < props.min) {
isValid = false;
}
if (props.max != null && +text > props.max) {
isValid = false;
}
if (props.minLength != null && text.length < props.minLength) {
isValid = false;
}
dispatch({ type: INPUT_CHANGE, value: text, isValid: isValid });
};
const lostFocusHandler = () => {
dispatch({ type: INPUT_BLUR });
};
const inputRef = useRef();
const getFormValue = () => {
const inputValue = props.initialValue
? props.initialValue
: inputState.value;
if (props.date) {
return formatDate(inputValue).toString();
}
return inputValue;
};
return (
<View style={{ ...props.style, ...styles.container }}>
<TextInput
ref={mergeRefs([inputRef, ref])}
{...props}
value={getFormValue()}
onChangeText={textChangeHandler}
onBlur={lostFocusHandler}
/>
{!inputState.isValid && inputState.touched && (
<TouchableOpacity onPress={() => inputRef.current.focus()}>
<View style={{ ...props.style, ...styles.errorContainer }}>
<Text
testID="Auth.errorMessage"
style={{ color: props.errorTextColor, ...styles.errorText }}
>
{props.errorText}
</Text>
</View>
</TouchableOpacity>
)}
</View>
);
});
const styles = StyleSheet.create({
container: { flex: 1 },
errorContainer: {
marginVertical: 5,
},
errorText: {
fontSize: 13,
},
});
Input.displayName = 'Input'; //This is here only to make esLint happy
Input.propTypes = {
date: PropTypes.bool,
onInputChange: PropTypes.func,
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
initialValue: PropTypes.any,
initiallyValid: PropTypes.bool,
required: PropTypes.bool,
email: PropTypes.bool,
min: PropTypes.number,
max: PropTypes.number,
minLength: PropTypes.number,
style: PropTypes.object,
errorText: PropTypes.string,
errorTextColor: PropTypes.string,
};
export default Input;
好吧,我想我在找到解決方案之前忘了回答這個問題。 這有點 hacky,但我只是將 getFormValue 的內容包裝在 5ms 超時中,這足以防止它出錯。
const getFormValue = () => {
setTimeout(() => {
const inputValue = props.initialValue
? props.initialValue
: inputState.value;
if (props.date) {
return formatDate(inputValue).toString();
}
return inputValue;
}, 5);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.