如何从 TextInput(onChange 或 onTextChange)创建 rxjs Observable

Posted

技术标签:

【中文标题】如何从 TextInput(onChange 或 onTextChange)创建 rxjs Observable【英文标题】:How to create an rxjs Observable from TextInput (either onChange or onTextChange) 【发布时间】:2021-10-28 04:40:52 【问题描述】:

我想根据在 React Native TextInput 组件上触发的更改事件创建一个可观察对象。 TextInput 带有我知道的 2 个更改道具(onChangeTextonChange)。据我所知,如果你想访问本地事件,你需要使用onChange,你需要使用onChange

我对原生事件对象了解不多。我正在尝试使用 fromEvent 创建一个可观察的 rxjs。

首先我在我的功能组件中创建了一个引用,如下所示:

const sqftRef = useRef().current

然后我将此引用附加到TextInput 组件,如下所示:

 <TextInput
    ref=sqftRef // attach a ref 
    label='Sqft'
    mode='flat'
    textContentType='none'
    autoCapitalize='none'
    keyboardType='numeric'
    autoCorrect=false
    value=String(formValues.sqft)
    dense
    underlineColor=colors.colorOffWhite
    onChangeText=(text) => setText(text)
    onChange=e => 
        // somehow create an observable from this event ???
    
    style=styles.inputStyles
    theme=inputTheme
 />

我尝试像这样使用 fromEvent 创建一个 Observable,但它不起作用。我得到 undefined is not an object(评估 target.addEventListener):

fromEvent(sqftRef, 'onChange').subscribe(value => console.log(value))

我知道我的方法全错了。希望有人能指出我正确的方向。

【问题讨论】:

【参考方案1】:

我会将您需要的事件发送到主题中,然后在代码的其他部分订阅主题。

这是一个简单的 React 示例,可以帮助您入门

function App() 

  const textChange = new Subject<string>();


  useEffect(() => 
    // subscribe to 
    const subscription = textChange.asObservable().subscribe(console.log)
    return () => subscription.unsubscribe()
  , [])




  // Emit events with a subject
  return <textarea onChange=(e) => 
    textChange.next(e.target.value)
  >
  </textarea>


render(<App />, document.getElementById('root'));

在此处查看示例:https://stackblitz.com/edit/react-ts-akoyfv

【讨论】:

我尝试了几种不同的方法。最初我得到这样的参考: const sqftRef = useRef().current 然后它总是参考电流。但是这并不能正常工作,因为据我所知,您必须将 ref 本身附加到 textinput,而不是当前值。当我使用您的解决方案时,我得到“无效的事件目标” @JoMomma 我用不同的想法更新了我的答案。它使用React而不是ReactNative,但原理还是一样的。 我不知道为什么,但是当我尝试像你这样的解决方案时,next() 函数只会在第一次触发....它没有完成或出错,但每隔一个下一个() 调用什么都不做。 我知道原因了。我将其添加到我的答案中。记住订阅很重要,这样它就不会在状态更改时重新创建。【参考方案2】:

我认为问题在于将current 直接分配给sqftRef。尝试在没有current 的情况下定义它,但在创建Observable 时使用current,如下所示:

const sqftRef = useRef();

然后在useEffect 中创建Observable 以确保DOM 准备就绪:

useEffect(() => 
  fromEvent(sqftRef.current, 'onChange').subscribe((value) =>
    console.log(value)
  );
);

【讨论】:

我也发现了这一点,但现在我得到一个错误:'无效的事件目标'。也许是因为它是***代码?在我尝试创建流之前,是否还没有附加参考?也许我会尝试在 useEffect 中设置它.... 是的,您应该在useEffect 中使用它。抱歉,我忘了提。【参考方案3】:

好的,我在 Amer Yousuf 和 A​​lex Fallenstedt 的帮助下解决了这个问题。

我做了类似于 Alex 建议的事情,修改了他的 React Native 解决方案。他的解决方案对我不起作用的一个原因是,使用useRef 挂钩来防止在每次渲染时重新创建 Observable 非常重要。如果 observable 被重新创建(在重新渲染时)并且 useEffect 没有再次运行,那么我们将没有对新(重新创建)的 observable 的活动订阅(useEffect 不再运行)。这就是为什么我对 sqft$.next 的调用最初只被调用一次(第一次直到我们重新渲染)。

我的解决方案如下所示:

let sqft$ = useRef(new BehaviorSubject(0)).current

useEffect(() => 
        const sub = sqft$.subscribe(
            next: (val) => 
                // just testing stuff out here
                updateForm('sqft', val)
                updateForm('lot', val * 2)
            
        )
      // this is only relevant to my use case
      if (activeReport) sqft$.next(activeReport.sqft)
      return () => sub.unsubscribe()

   , [activeReport])

当然,我将其称为onChangeText

onChangeText=(text) => 
   sqft$.next(text)

所以这现在正在工作。我仍然觉得使用onChange(e =&gt; ...stuff) 可能有更好的方法。我会暂时保留这个问题,以防有人可以分解如何使用 nativeEvent 执行此操作,或者向我解释如何访问 TextInput 组件的事件。

【讨论】:

请问我建议的解决方案到底有什么问题? 它产生一个错误:“未定义不是一个对象(评估'target.addEventListener')。我不知道为什么。我们需要访问nativeEvent吗?我们有错误的事件名称('onChange')?我还不知道,但这个解决方案不起作用。

以上是关于如何从 TextInput(onChange 或 onTextChange)创建 rxjs Observable的主要内容,如果未能解决你的问题,请参考以下文章

如何在 TextInput 中获取 $ 符号和逗号分隔符?

React Native TextInput 不允许输入/文本更改

onChange 仅在 2 个文本输入后触发

TextInput

闪亮:从具有多个值的 textInput 中子集表

TextInput 忽略 React Native 上的双击(句点)