npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

remote-data-rtk

v1.0.0

Published

ADT for @reduxjs/toolkit/query

Downloads

7

Readme

ADT compatible with '@reduxjs/toolkit/query/react'

Prerequisites:

Installation

yarn add remote-data-rtk

Prior art:

Usage example from this repo

Go to src/dev/demo/index.tsx for comparison with classic approach

export const WithRemoteRTKDemoCombined2Queries: FC = () => {
  const users: RemoteData<RemoteError, APIUser[]> = api.useGetUsersQuery();
  const todos: RemoteData<RemoteError, APITodo[]> = api.useGetTodosQuery();

  const data = pipe(
    remote.combine({ users, todos }),
    remote.map(({ users, todos }) => ({
      users: users.map((user) => ({
        ...user,
        fullName: user.name + user.username,
      })),
      todos,
    })),
  );

  return (
    <div className="remote">
      <RenderRemote
        data={data}
        success={(data) => <UsersWithTodosComponent users={data.users} todos={data.todos} />}
        initial={<div>INITIAL</div>}
        failure={() => <div>ERROR</div>}
        pending={<div>SKELETON</div>}
      />
    </div>
  );
};

API

remote.initial

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };

const initialUsers: RemoteData<RemoteError, User[]> = remote.initial;

remote.pending

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };

const pendingUsersWithData: RemoteData<RemoteError, User[]> = remote.pending([{name: "John", age: 20}]);

const pendingUsers: RemoteData<RemoteError, User[]> = remote.pending();

remote.failure

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };

const failureUsers: RemoteData<RemoteError, User[]> = remote.failure(new Error('failed to fetch'));
// left part can be whatever you need
const failureUsersCustomError: RemoteData<{reason: string}, User[]> = remote.failure({reason: 'failed to fetch'});

remote.success

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };

const successUsers: RemoteData<RemoteError, User[]> = remote.success([{name: "John", age: 20}])

remote.isInitial

import { remote } from 'remote-data-rtk';

remote.isInitial(remote.initial) // true
remote.isInitial(remote.pending()) // false

remote.isPending


import { remote } from 'remote-data-rtk';

remote.isPending(remote.pending()) // true
remote.isPending(remote.failure(new Error())) // false

remote.isFailure

import { remote } from 'remote-data-rtk';

remote.isFailure(remote.failure(new Error())) // true
remote.isFailure(remote.success([])) // false

remote.isSuccess

import { remote } from 'remote-data-rtk';

remote.isSuccess(remote.success([])) // true
remote.isSuccess(remote.pending([])) // false

remote.map

import { remote, RemoteError } from 'remote-data-rtk';
import { pipe } from 'fp-ts/function';

type User = { name: string; age: number };
type UserInfo = string; // name + age

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})
const remoteUserName: RemoteData<RemoteError, UserInfo> = pipe(remoteUser, remote.map(user => `${user.name} ${user.age}`))

remote.mapLeft

import { remote, RemoteError } from 'remote-data-rtk';
import { pipe } from 'fp-ts/function';

const remoteUser: RemoteData<RemoteError, string> = remote.failure(new Error('could not fetch'))
const remoteUserLeftMapped: RemoteData<{custom: string}, string> = pipe(remoteUser, remote.mapLeft(error => ({custom: String(error)})))

remote.fold

import { remote, RemoteError } from 'remote-data-rtk';
import { pipe, identity } from 'fp-ts/function';
import { option } from 'fp-ts';

type User = { name: string; age: number };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})

const user: string = pipe(
    remoteUser,
    remote.map(user => `${user.name} ${user.age}`),
    remote.fold(
        () => 'nothing is fetched',
        option.fold(() => 'just pending', (userInfo) => `info: ${userInfo}. pending again for some reason`),
        String,
        identity,
    )
)

remote.getOrElse

import { remote, RemoteError } from 'remote-data-rtk';
import { pipe } from 'fp-ts/function';

type User = { name: string; age: number };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})

const user: string = pipe(
    remoteUser,
    remote.map(user => `${user.name} ${user.age}`),
    remote.getOrElse(() => 'no user was fetched')
)

remote.toNullable

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})

const nullableUser: User | null = remote.toNullable(remoteUser);

remote.fromOption

import { remote, RemoteError } from 'remote-data-rtk';
import { option } from 'fp-ts';
import { Option } from 'fp-ts/Option';

type User = { name: string; age: number };

const optionUser: Option<User> = option.some({name: 'John', age: 20})

const remoteFromOptionUser: RemoteData<RemoteError, User> = remote.fromOption(optionUser, () => new Error('option was none'))

remote.toOption

import { remote, RemoteError } from 'remote-data-rtk';
import { Option } from 'fp-ts/Option';

type User = { name: string; age: number };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})

const optionUser: Option<User> = remote.toOption(remoteUser);

remote.fromEither

import { remote, RemoteError } from 'remote-data-rtk';
import { Either, right } from 'fp-ts/lib/Either';

type User = { name: string; age: number };

const eitherUser: Either<RemoteError, User> = right({name: 'John', age: 20})

const remoteFromEitherUser: RemoteData<RemoteError, User> = remote.fromEither(eitherUser)

remote.toEither

import { remote, RemoteError } from 'remote-data-rtk';
import { Either } from 'fp-ts/lib/Either';
import { pipe } from 'fp-ts/function';

type User = { name: string; age: number };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})

const eitherUser: Either<RemoteError, User> = pipe(
    remoteUser,
    remote.toEither(() => new Error('initial'), () => new Error('pending'))
)

remote.chain

import { remote, RemoteError } from 'remote-data-rtk';
import { pipe } from 'fp-ts/function';

type User = { name: string; age: number };
type UserInfo = string; // name + age

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20})
const chained = pipe(
    remoteUser,
    remote.chain<RemoteError, User, UserInfo>((user) => remote.success(`${user.name} ${user.age}`))
)

remote.sequence

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };
type City = { title: string };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20});
const remoteCity: RemoteData<RemoteError, City> = remote.success({title: "New Orleans"});

const remoteCombined: RemoteData<RemoteError, [User, City]> = remote.sequence(remoteUser, remoteCity)

remote.combine

import { remote, RemoteError } from 'remote-data-rtk';

type User = { name: string; age: number };
type City = { title: string };

const remoteUser: RemoteData<RemoteError, User> = remote.success({name: "John", age: 20});
const remoteCity: RemoteData<RemoteError, City> = remote.success({title: "New Orleans"});

const remoteCombined: RemoteData<RemoteError, {user: User; city: City}> = remote.combine({user: remoteUser, city: remoteCity})

RenderRemote

export type RenderRemoteProps<E, A> = {
    /** Remote data needs to be rendered */
    data: RemoteData<E, A>;
    /** Render content function on failure state */
    failure?: (e: E) => ReactNode;
    /** Render content constant on initial state */
    initial?: ReactNode;
    /** Render content constant on pending state */
    pending?: ReactNode;
    /** Render content function on pending with data (refetching) state */
    refetching?: (data: A) => ReactNode;
    /** Render content function on success state */
    success: (data: A) => ReactNode;
};

CHANGELOG

0.0.1 17.08.2022

  • Initial release

0.0.2 17.08.2022

  • Removed useless dependency

1.0.0 30.08.2022

  • Removed RTK suffix
  • Removed useless generics (i.e. getOrElse<E, A> -> getOrElse)
  • Renamed sequenceS -> combine
  • Renamed sequenceT -> sequence
  • Fixed fp-ts peer import
  • Add mapLeft