re-rxjs / react-rxjs

React bindings for RxJS
https://react-rxjs.org
MIT License
542 stars 17 forks source link

Proposal to support event handlers #267

Closed pastelmind closed 2 years ago

pastelmind commented 2 years ago

React's basic data flow is, roughly:

User interaction --(A)--> State change --(B)--> View update

Currently, react-rxjs only handles part B. This proposal discusses part A.


When using React and RxJS, there are two ways of handling events.

  1. Use regular React event handlers, forgoing the benefits of Observables
  2. Use fromEvent directly on DOM elements, working outside React's event system

Neither is clearly desirable. Instead, what if react-rxjs provided a helper that creates event handlers using RxJS operators?

Here is a tentative type signature for such a helper:

function useHandler<E = React.Event>(
  factory: (event$: Observable<E>) => Observable<T>,
  dependencyArray: unknown[],
): [(event: E) => void, Observable<T>]

E.g.

import {useHandler} from '@react-rxjs/utils'

const MyComponent = () => {
  const [handler, observable$] = useHandler<React.MouseEvent>(
    // This callback creates an observable
    // When the component mounts, the observable is subscribed automatically.
    // When the component unmounts, the observable is unsubscribed.
    (event$) => event$.pipe(/* ... */),
    [/* dependency array */]
  )

  // Here, we can compose observable$ to create another observable

  return (
    <button onClick={handler}>
      Click me
    </button>
  )
}

(We could flesh out the details of useHandler() later)

This would provide a better story for React devs who want to use RxJS (or vice versa).

voliva commented 2 years ago

React-RxJS is more suited for global state. We already have createSignal that's used to handle user input. Your example would become:

import { createSignal } from '@react-rxjs/utils';

const [observable$, handler] = createSignal();

// Compose observable$ to create other observables

const MyComponent = () => {
  return <button onClick={handler}>
    Click me
  </button>
}

Your proposal is quite close to the approach https://github.com/crimx/observable-hooks are using.