Javascript React本地听写在iOS上突然切字

Javascript React本地听写在iOS上突然切字,javascript,ios,reactjs,react-native,Javascript,Ios,Reactjs,React Native,在iOS中对文本输入使用听写时,听写会在单词之间突然结束。这不是以前React Native 53上的问题。移动到版本54+会导致此行为 下面是产生错误的代码示例: import React, { Component } from 'react'; import { TextInput } from 'react-native'; export default class App extends Component { state = { value: '' } onChangeTex

在iOS中对文本输入使用听写时,听写会在单词之间突然结束。这不是以前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 }}
        />
    );
  }
}
import React,{Component}来自'React';
从“react native”导入{TextInput};
导出默认类应用程序扩展组件{
状态={值:“”
onChangeText=value=>console.log(value)| | this.setState({value})
render(){
返回(
);
}
}
它似乎来自
onChangeText
方法,因为当我将函数
onChangeText
放入
onBlur
方法时,它工作得很好。 但是使用
onBlur
使得不可能使用
onEditing
onSubmitEditing
,因为它在
onEditing
onSubmitEditing
方法之后触发
setState

有人找到了解决办法吗


github react native项目上出现了一个问题。

因此这是react native的一个短消息

口述失败的原因是,当您口述时,组件会重新呈现它自己。当它重新呈现时,Siri面板最小化,因此听写突然结束

为了解决这个问题,我创建了一个TextInput包装器组件,该组件依赖于
shouldComponentUpdate
在值更改时阻止我的TextInput包装器重新呈现

现在,我们不是立即重新渲染,而是仅在特定时间量的去抖动后设置状态。(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;
从“React”导入React;
从“lodash.debounce”进口debounce;
从“道具类型”导入道具类型;
从“react native”导入{TextInput};
const CHANGE_TEXT_DELAY_直到_DISPATCH=700;
//强制执行指示安全,以便siri可以听到1个以上的单词
类DictionSafeTextInput扩展React.Component{
//
建造师(道具){
超级(道具);
这个.onValueChange延迟了=
解除绑定(this.onValueChangeDelayed.bind(this),更改文本延迟直到发送);
此.state={
价值:道具价值,
};
}
组件将接收道具(下一步){
if(this.props.value!==nextrops.value){
此.onValueChangeDelayed(nextProps.value);
}
}
shouldComponentUpdate(下一步,下一步状态){
const pastProps=this.props;
常数shoudlUpdate=(
//pastProps.value!==nextrops.value
// ||
nextState.value!==this.state.value
||
pastProps.style!==nextrops.style
||
pastProps.editable!==nextrops.editable
||
pastProps.onContentSizeChange!==nextProps.onContentSizeChange
||
pastProps.onSubmitEditing!==nextrops.onSubmitEditing
||
pastProps.onChangeText!==nextrops.onChangeText
||
pastProps.onFocus!==nextProps.onFocus
||
pastProps.onBlur!==nextrops.onBlur
||
pastProps.innerTextInputRef!==nextProps.innerTextInputRef
||
pastProps.blurOnSubmit!==nextrops.blurOnSubmit
||
pastProps.autoFocus!==nextrops.autoFocus
||
pastProps.pointerEvents!==nextProps.pointerEvents
||
pastProps.maxLength!==nextProps.maxLength
||
pastProps.returnKeyType!==nextProps.returnKeyType
||
pastProps.placeholderTextColor!==nextrops.placeholderTextColor
||
pastProps.placeholder!==nextrops.placeholder
||
pastProps.underlineColorAndroid!==nextProps.underlineColorAndroid
||
pastProps.autoCorrect!==nextrops.autoCorrect
||
pastProps.multiline!==nextrops.multiline
||
pastProps.autoCapitalize!==nextrops.autoCapitalize
||
pastProps.keyboardType!==nextProps.keyboardType
||
pastProps.numberOfLines!==nextProps.numberOfLines
||
pastProps.defaultValue!==nextProps.defaultValue
||
pastProps.DictionSafety!==nextProps.DictionSafety
);
返回并更新;
}
组件将卸载(){
此.onValueChangeDelayed.cancel();
if(this.onSubmitEditingTimeout!=null){
clearTimeout(this.onSubmitEditingTimeout);
this.onSubmitEditingTimeout=null;
}
}
onValueChangeDelayed(新值){
if(newValue!==this.state.value){
这是我的国家({
value:newValue,
});
}
}
render(){
常数{
口述安全,
一旦更改文本,
安布尔,
innerTextInputRef,
在submitediting上,
}=这是道具;
if(听写安全和更改文本(&onChangeText){
返回(
{
if(innerTextInputRef!=null){
innerTextInputRef(r);
}
}}
{……这个。道具}
value={this.state.value}
onChangeText={(newValue)=>{
if(this.props.onChangeText){
this.props.onChangeText(newValue);
}
}}
onBlur={()=>{
此.onValueChangeDelayed.flush();
if(onBlur){
onBlur();
}
}}
onSubmitEditing={()=>{
此.onValueChangeDelayed.flush();
如果(正在Submitediting){
this.onSubmitEditingTimeout=设置超时(()=>{
onSubmitEditing();
},更改\u文本\u延迟\u直到\u发送);
}
}}
/>
);
}
返回(
);
}
}
DictionSafeTextInput.defaultProps={
口述安全:正确,
};
DictionSafeTextInput.propTypes={
innerTextInputRef:PropTypes.oneOfType([
PropTypes.func,
PropTypes.object,
]),
onChangeText:PropTypes.func,
onBlur:PropTypes.func,
onSubmitEditing:PropTypes.func,
口述安全:PropTypes.bool,
pointerEvents:PropTypes.oneOf([
“无框”,
“没有”,
“仅限盒子”,
“自动”,
])