在iOS中的TextInput上使用听写时,听写会在单词之间突然结束。这以前不是React Native 53的问题。移动到版本54+会导致此行为。
下面是产生该错误的代码示例:
import React, { Component } from 'react';
import { TextInput } from 'react-native';
export default class App extends Component {
state = { value: '' }
onChangeText = value => console.log(value) || this.setState({ value })
render() {
return (
<TextInput
onChangeText={this.onChangeText}
value={this.state.value}
style={{ borderWidth: 2, borderColor: 'black', width: 200, height: 48 }}
/>
);
}
}
似乎来自
onChangeText
方法,因为当我将函数onChangeText
放入onBlur
方法中时,它运行良好。但是,使用
onBlur
使得无法使用onEditing
或onSubmitEditing
,因为它会在setState
和onEditing
方法之后触发onSubmitEditing
。有人找到了解决方案吗?
在github react本机项目here上打开了一个问题。
最佳答案
因此,这是一个反应性的缺点。
听写失败的原因是,当您听写时,组件会重新渲染自身。每当它重新渲染时,Siri的面板就会最小化,因此听写将很快结束。
为了解决此问题,我创建了一个TextInput包装器组件,该组件依赖shouldComponentUpdate
来阻止我的TextInput包装器在值更改时重新呈现。
现在,我们无需立即重新渲染,而是仅在经过特定时间的反跳之后才setState
。 (从500-1500的任何值都可以使用)
试试看,让我知道它是否适合您。
import React from 'react';
import debounce from 'lodash.debounce';
import PropTypes from 'prop-types';
import { TextInput } from 'react-native';
const CHANGE_TEXT_DELAY_UNTIL_DISPATCH = 700;
// enforces dication safety so that siri can hear more than 1 words
class DictationSafeTextInput extends React.Component {
//
constructor(props) {
super(props);
this.onValueChangeDelayed =
debounce(this.onValueChangeDelayed.bind(this), CHANGE_TEXT_DELAY_UNTIL_DISPATCH);
this.state = {
value: props.value,
};
}
componentWillReceiveProps(nextProps) {
if (this.props.value !== nextProps.value) {
this.onValueChangeDelayed(nextProps.value);
}
}
shouldComponentUpdate(nextProps, nextState) {
const pastProps = this.props;
const shoudlUpdate = (
// pastProps.value !== nextProps.value
// ||
nextState.value !== this.state.value
||
pastProps.style !== nextProps.style
||
pastProps.editable !== nextProps.editable
||
pastProps.onContentSizeChange !== nextProps.onContentSizeChange
||
pastProps.onSubmitEditing !== nextProps.onSubmitEditing
||
pastProps.onChangeText !== nextProps.onChangeText
||
pastProps.onFocus !== nextProps.onFocus
||
pastProps.onBlur !== nextProps.onBlur
||
pastProps.innerTextInputRef !== nextProps.innerTextInputRef
||
pastProps.blurOnSubmit !== nextProps.blurOnSubmit
||
pastProps.autoFocus !== nextProps.autoFocus
||
pastProps.pointerEvents !== nextProps.pointerEvents
||
pastProps.maxLength !== nextProps.maxLength
||
pastProps.returnKeyType !== nextProps.returnKeyType
||
pastProps.placeholderTextColor !== nextProps.placeholderTextColor
||
pastProps.placeholder !== nextProps.placeholder
||
pastProps.underlineColorAndroid !== nextProps.underlineColorAndroid
||
pastProps.autoCorrect !== nextProps.autoCorrect
||
pastProps.multiline !== nextProps.multiline
||
pastProps.autoCapitalize !== nextProps.autoCapitalize
||
pastProps.keyboardType !== nextProps.keyboardType
||
pastProps.numberOfLines !== nextProps.numberOfLines
||
pastProps.defaultValue !== nextProps.defaultValue
||
pastProps.dictationSafety !== nextProps.dictationSafety
);
return shoudlUpdate;
}
componentWillUnmount() {
this.onValueChangeDelayed.cancel();
if (this.onSubmitEditingTimeout != null) {
clearTimeout(this.onSubmitEditingTimeout);
this.onSubmitEditingTimeout = null;
}
}
onValueChangeDelayed(newValue) {
if (newValue !== this.state.value) {
this.setState({
value: newValue,
});
}
}
render() {
const {
dictationSafety,
onChangeText,
onBlur,
innerTextInputRef,
onSubmitEditing,
} = this.props;
if (dictationSafety && onChangeText) {
return (
<TextInput
ref={(r) => {
if (innerTextInputRef != null) {
innerTextInputRef(r);
}
}}
{...this.props}
value={this.state.value}
onChangeText={(newValue) => {
if (this.props.onChangeText) {
this.props.onChangeText(newValue);
}
}}
onBlur={() => {
this.onValueChangeDelayed.flush();
if (onBlur) {
onBlur();
}
}}
onSubmitEditing={() => {
this.onValueChangeDelayed.flush();
if (onSubmitEditing) {
this.onSubmitEditingTimeout = setTimeout(() => {
onSubmitEditing();
}, CHANGE_TEXT_DELAY_UNTIL_DISPATCH);
}
}}
/>
);
}
return (
<TextInput
{...this.props}
/>
);
}
}
DictationSafeTextInput.defaultProps = {
dictationSafety: true,
};
DictationSafeTextInput.propTypes = {
innerTextInputRef: PropTypes.oneOfType([
PropTypes.func,
PropTypes.object,
]),
onChangeText: PropTypes.func,
onBlur: PropTypes.func,
onSubmitEditing: PropTypes.func,
dictationSafety: PropTypes.bool,
pointerEvents: PropTypes.oneOf([
'box-none',
'none',
'box-only',
'auto',
]),
autoCorrect: PropTypes.bool,
style: PropTypes.oneOfType([
PropTypes.object,
PropTypes.array,
PropTypes.number,
]),
onContentSizeChange: PropTypes.func,
editable: PropTypes.bool,
// eslint-disable-next-line
underlineColorAndroid: PropTypes.any,
value: PropTypes.string,
multiline: PropTypes.bool,
placeholder: PropTypes.string,
// eslint-disable-next-line
placeholderTextColor: PropTypes.any,
returnKeyType: PropTypes.oneOf([
// Cross-platform
'done',
'go',
'next',
'search',
'send',
// Android-only
'none',
'previous',
// iOS-only
'default',
'emergency-call',
'google',
'join',
'route',
'yahoo',
]),
autoFocus: PropTypes.bool,
blurOnSubmit: PropTypes.bool,
autoCapitalize: PropTypes.oneOf([
'none',
'sentences',
'words',
'characters',
]),
keyboardType: PropTypes.oneOf([
'default',
'email-address',
'numeric',
'phone-pad',
'number-pad',
'ascii-capable',
'numbers-and-punctuation',
'url',
'name-phone-pad',
'decimal-pad',
'twitter',
'web-search',
'visible-password',
]),
onFocus: PropTypes.func,
numberOfLines: PropTypes.number,
defaultValue: PropTypes.string,
maxLength: PropTypes.number,
};
export default DictationSafeTextInput;