Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reactive components #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Reactive components #9

wants to merge 2 commits into from

Conversation

kosich
Copy link
Owner

@kosich kosich commented Apr 19, 2021

Intro

This feature introduces a reactive components style (like it Recks) with React's hook API available:

let Component = createComponent$((props$: Observable<SomeProps>) => {
  // this function initialises component and is called only once
  // so it's a good place to declare callbacks
  let onClick = () => alert('Wow! Clicked!');

  // or use hooks
  let contextData$: Observable<any> = useHook$(() => {
    // call one or many hooks here
    return useContext(SOME_CONTEXT);
  });

  // and we return either JSX or a stream of JSX (Observable<JSX>)
  return <div>
    <$>{
      // and we can still use <$> elements to display dynamic data
      props$.pipe(map(p => p.id))
    }</$>
    <button onClick={ onClick }>click me</button>
  </div>
})

Here's an example using react-router useParams hook with data fetching:

import { switchMap } from 'rxjs/operators';
import { useParams } from 'react-router-dom';
import { $, createComponent$, useHook$ } from 'react-rxjs-elements';

// create a component for route /page/:id
export default createComponent$(() => {
  // get route params as a stream
  let params$ = useHook$(useParams);

  // map it to data fetching from some web API
  let data$ = params$.pipe(
    switchMap(p => fetch('/api/' + p.id))
  );

  // here we can either return a stream of JSX
  return data$.pipe(map(d => <h1>{ d.title }</h1>));
  // or display our data in a $ element
  return <$h1>{ data$.pipe(map(d => <h1>{ d.title })) }</$h1>
})

And here's a small app, made with createComponent$: https://stackblitz.com/edit/react-rxjs-elements-components-alpha

API

react-rxjs-elements now additionaly exposes:

  • createComponent$(fn: (props$: Observable<Props>) => JSX | Observable<JSX>) -- create a stream component
  • useHook$(fn: () => any)-- use a React hook (or any 3rdparty hook) inside a stream component
  • useMount$() and useUnmount$() -- both return : Observable<void>. Predefined hooks that will emit a void value when the component is mounted and unmounted

Try it

This feature is available in the @next version of this library and currently can be tried via npm i react-rxjs-elements@next or at stackblitz playground online.

Please, share your thoughts and feedback in this thread -- this helps a lot!

Have a good day :)

@kosich
Copy link
Owner Author

kosich commented Apr 27, 2021

NOTE: props$ should have a .current property, so that instead of

let Comp = createComponent$(props$ => {
  let handler = props$
  .pipe(
    map(() => () => {
      // ... do other stuff
      // then call something from current props$
      props.current.onClick();
    }}
  )

  return <$button onClick={ handler }/>
});

We could do:

let Comp = createComponent$(props$ => {
  let handler = () => {
    // ... do other stuff
    // then call something from current props$
    props.current.onClick();
  };

  return <button onClick={ handler }/>
});

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant