草庐IT

javascript - React native 听写在 iOS 上突然削减单词

coder 2024-01-22 原文

在 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方法就像我把我的函数 onChangeTextonBlur方法它运作良好。 但是使用 onBlur无法使用 onEditing也不onSubmitEditing因为它会触发 setStateonEditing之后和 onSubmitEditing方法。

有人找到解决办法了吗?

在 github react native 项目上打开了一个问题 here .

最佳答案

所以这是react-native的缺点。

听写失败的原因是组件在您听写时自行重新呈现。每当它重新渲染 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;

关于javascript - React native 听写在 iOS 上突然削减单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50242059/

有关javascript - React native 听写在 iOS 上突然削减单词的更多相关文章

  1. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  2. ruby - 如何验证 IO.copy_stream 是否成功 - 2

    这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下

  3. Ruby 文件 IO 定界符? - 2

    我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的

  4. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  5. ruby - 正则表达式将非英文字母匹配为非单词字符 - 2

    @raw_array[i]=~/[\W]/非常简单的正则表达式。当我用一些非拉丁字母(具体来说是俄语)尝试时,条件是错误的。我能用它做什么? 最佳答案 @raw_array[i]=~/[\p{L}]/使用西里尔字符进行测试。引用:http://www.regular-expressions.info/unicode.html#prop 关于ruby-正则表达式将非英文字母匹配为非单词字符,我们在StackOverflow上找到一个类似的问题: https://

  6. Python 刷Leetcode题库,顺带学英语单词(31) - 2

    ValidPalindromeGivenastring,determineifitisapalindrome,consideringonlyalphanumericcharactersandignoringcases. [#125]Example:"Aman,aplan,acanal:Panama"isapalindrome."raceacar"isnotapalindrome.Haveyouconsiderthatthestringmightbeempty?Thisisagoodquestiontoaskduringaninterview.Forthepurposeofthisproblem

  7. ruby - 为什么不能使用类IO的实例方法noecho? - 2

    print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上

  8. ruby-on-rails - 使用 javascript 更改数据方法不会更改 ajax 调用用户的什么方法? - 2

    我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的

  9. ruby - 如何在 Cucumber 步骤定义中使单词可选? - 2

    我在下面有一个步骤定义,它执行我想要它执行的操作,即它根据“PAGES”哈希的“page”元素检查页面的url。Then(/^Ishould(still)?beatthe"(.*)"page$/)do|still,page|BROWSER.url.should==PAGES[page]end步骤定义用于两者我应该在...页面我应该还在...页面但是,我不需要将“still”传递到block中。我只需要它是可选的以匹配步骤但不传递到block中。我该怎么做?谢谢。 最佳答案 您想将“静止”组标记为非捕获。这是通过使用?:启动组来完成的

  10. ruby - 在 Mechanize 中使用 JavaScript 单击链接 - 2

    我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan

随机推荐