[Example #3] Fetch Data By User Input

by redneckz

HTML

<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/rxjs/bundles/rxjs.umd.min.js"></script>
<script src="https://unpkg.com/@redneckz/react-rxjs@0.0.4/dist/index.min.js"></script>

CSS

.post__title {
    font-size: large;
    font-weight: bold;
}

Babel + JSX

const { from } = rxjs;
const { map, distinctUntilChanged, debounceTime, switchMap } = rxjs.operators;
const { reactive, handle } = ReactRxjs;

const PostsSearchForm = reactive(
  () => from(fetchUsers()).pipe(
  	map(possibleUsers => ({ possibleUsers }))
  )
)(({ author, onChangeAuthor, possibleUsers = [] }) => (
  <section>
    <input value={author} onChange={onChangeAuthor} list="possibleUsers" />
    <datalist id="possibleUsers">
      {possibleUsers.map(({ username, name }) => (
        <option value={username} label={name} />
      ))}
    </datalist>
  </section>
));

const Posts = reactive(
  props$ => props$.pipe(
    map(({ author }) => author),
    distinctUntilChanged(),
    debounceTime(300),
    switchMap(fetchPostsByAuthor),
    map(posts => ({ posts }))
  )
)(
  ({ posts = [] }) => (
    <section>
      {posts.map(({ id, title, body }) => (
        <Post key={id} title={title}>{body}</Post>
      ))}
      {posts.length === 0 && <strong>Nothing found</strong>}
    </section>
  )
);

const FilteredPosts = reactive(
	handle('onChangeAuthor',
  	map(({ target: { value } }) => ({ author: value }))
  )
)(
  ({ author, onChangeAuthor }) => (
    <section>
      <PostsSearchForm author={author} onChangeAuthor={onChangeAuthor} />
      <hr />
      <Posts author={author} />
    </section>
  )
);

function Post({ title, children }) {
  return (
    <article>
      <header className="post__title">{title}</header>
      <p>{children}</p>
    </article>
  );
}

async function fetchUsers() {
  const response = await fetch('https://jsonplaceholder.typicode.com/users');
  return response.json();
}

async function fetchUserByName(username) {
  const response = await fetch(
  	`https://jsonplaceholder.typicode.com/users?username=${username}`
  );
  const [user] = await response.json();
  return user;
}

async function fetchPostsByAuthor(author) {
  const { id: authorId } = await fetchUserByName(author) || {};
  if (!authorId) return [];
  const response = await...