DEV Community

Discussion on: What React RxJS libs do You Use?

Collapse
 
wolfhoundjesse profile image
Jesse M. Holmes • Edited

If I wanted to return an array of JSX, is there a better way than:

const api1$ = useMemo(() => 
  fromFetch('http://api1.dev').pipe(
    mergeMap(res => res.json())
  ),[])

const api2$ = useMemo(() => 
  fromFetch('http://api2.dev').pipe(
    mergeMap(res => res.json())
  ),[])

const services$ = useMemo(() =>
  forkJoin([api1$, api2$])
),[])

return <$>{ services$.pipe(
  map(items => items.map(
    item => <p key={item.id}> {item.description} </p>
  ))
)}
</$>
Enter fullscreen mode Exit fullscreen mode
Collapse
 
kosich profile image
Kostia Palchyk • Edited

Hey, Jesse!

Great question, a lot happening here :)

First, about observables inside render fn:

useMemo is fine, but it does not guarantee that the content will be preserved. Consider either using some useConst analogue, or moving Observables outside the render function.

const Component = () => {
  let time$ = useConst(() => timer(0, 1000));

  return <$div>{ timer$ }</$div>
};
Enter fullscreen mode Exit fullscreen mode

Also, check out this experimental update to the <$> library:

const Component = createComponent$(() => {
  let time$ = timer(0, 1000);

  return <$div>{ timer$ }</$div>
});
Enter fullscreen mode Exit fullscreen mode

The component function is executed only once, thus making it safe to create Observables here. This is a beta feature and I'm currently testing it. It's available in the @next npm version and can be trialled online More details at github/react-rxjs-elements/pull/9

Second, the double mapping

The services$.pipe( map(items => items.map( … thing always bothered me. There are also several solutions to it.

1: Use a separate component to render the list

function App() {
  let source$ = useConst(() => getData('/url/to/data'));

  return <$>{
    source$.pipe(
      map(response => <List items={response}/>)
    )
  }</$>
}
Enter fullscreen mode Exit fullscreen mode

2: Use rxjs-proxify to do the array.map in a more concise way:

export function App() {
  let source = useConst(() => proxify(getData('/url/to/data')));

  return <ul>
    <$>{
      source.map(i =>
        <li key={i.key}>{i.title}</li>
      )
    }</$>
  </ul>;
}
Enter fullscreen mode Exit fullscreen mode
Try this example in online playground

Proxify provides magic like proxify( of(42) ).toString() which returns an Observable<string>. So .map(…) in the example above creates another Observable, by calling .pipe(map( items => items.map(…) )) on the underlying Observable. More on the rxjs-proxify here

-

And just a side note: use ajax from rxjs/ajax to remove the

fromFetch('http://api2.dev').pipe(
  mergeMap(res => res.json())
);
// ≈
ajax('http://api2.dev');
Enter fullscreen mode Exit fullscreen mode

-

If that doesn't suit your needs — be sure to checkout other libs I mention, they are all pretty amazing.

Cheers 🙂