【问题标题】:How to create an rxjs Observable from TextInput (either onChange or onTextChange)如何从 TextInput(onChange 或 onTextChange)创建 rxjs Observable
【发布时间】: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))

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

【问题讨论】:

    标签: react-native rxjs event-handling react-native-textinput


    【解决方案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')?我还不知道,但这个解决方案不起作用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-11
    • 1970-01-01
    • 1970-01-01
    • 2020-07-26
    • 2016-09-06
    • 1970-01-01
    相关资源
    最近更新 更多