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

@throned/react-resource-ts

v0.1.1

Published

## Install

Downloads

4

Readme

throned ▲ react-resource-ts

Install

npm install --save @throned/react-resource-ts @throned/resource-ts

yarn add @throned/react-resource-ts @throned/resource-ts

@throned/react-resource-ts has @throned/resource-ts in dependencies, so it will be installed anyway.

Be aware that useResource hook uses AbortController so you may want to add a polyfill.

Intro

React Resource provides hooks and components for Resource ADT.

useResource hook gives you the ability to wrap your asynchronous operation into Resource data type and render each possible state of resource (Initial, Loading, Success, Failure components) as well as define your own matchers (Match).

import * as React from 'react'
import {isLoading} from '@throned/resource-ts'
import {getStateComponents, useResource} from '@throned/react-resource-ts'

type Dog = {message: string}

const loadDog = async (): Promise<Dog> => {
  return fetch('https://dog.ceo/api/breeds/image/random').then(res => {
    if (!res.ok) {
      throw new Error(res.statusText)
    }
    return res.json()
  })
}

const App = () => {
  const dog = useResource(loadDog, {defer: true})
  const State = getStateComponents(dog.resource)
  return (
    <React.Fragment>
      <State.Match states={['initial', 'loading']}>
        <button onClick={dog.run} disabled={isLoading(dog.resource)}>
          Show me doggo!
        </button>
        <State.Loading>
          <p>Loading...</p>
        </State.Loading>
      </State.Match>
      <State.Failure render={(error: Error) => <p>Oops! {error.message}</p>} />
      <State.Success>
        {({message}) => (
          <div>
            <h1>Nice</h1>
            <img src={message} alt="dog" />
            <button onClick={dog.run}>Show me more!</button>
          </div>
        )}
      </State.Success>
    </React.Fragment>
  )
}

API

useResource

const {cancel, reset, resource, run} = useResource<Params, Data, Error>(
  load,
  props,
)

load

(params: Params, config?: Config) => Promise<Data>

Function that returns a promise and may fail with Error type (Error type that provided is useResource type parameters). Accepts optional second parameter of type Config. Config is { signal: AbortController.signal } that you can pass into your fetch to enable cancellation.

props

type UseResourceProps<Params, Data, Error> = {
  cancellable?: boolean
  chain?: Resource<Params, unknown>
  defer?: boolean
  dependencies?: any[]
  onFailure?: (error: Error) => void
  onSuccess?: (data: Data) => void
  params?: Params
  skipLoadingFor?: number
}
cancellable

boolean = true

If true will use Abort Controller abort() to cancel previous load on subsequent load call.

chain

Resource<Params, unknown>

If chain is passed its resource.value will be used instead of params prop when load is executed by useResource. You can use chain to wait until another resource is in success state to get params from it. When chain is provided load function will be executed only when resource in chain is in success.

import {useResource, Success} from '@throned/react-resource-ts'
import {map} from '@throned/resource-ts'

type UserMovie = {movieId: string}

const getUserMovie = () => Promise.resolve({movieId: '1234'})
const getMovie = (id: string) => Promise.resolve({title: 'The Departed'})

const Component = () => {
  const user = useResource(getUserMovie)
  const movie = useResource(getMovie, {
    dependencies: [user.resource],
    chain: map(({movieId}: UserMovie) => movieId)(user.resource),
  })
  return (
    <Success of={movie.resource}>{movie => <h1>{movie.title}</h1>}</Success>
  )
}
defer

boolean = false

If you pass defer: true then load function won't be called automatically. To run load manually you have to call run.

dependencies

any[] = []

Works the same way as dependencies array in useEffect hook. If value of dependencies prop is changed between render useResource will execute load function. Be aware that if defer: true then load won't be executed.

onFailure

(error: Error) => void

Callback that is called when load rejects.

onSuccess

(data: Data) => void

Callback that is called when load resolves.

params

Params

These params will be provided as a first argument of load function. You can overwrite them when calling run function by passing new params to it. Will be ignored by automatic load execution if chain is provided.

skipLoadingFor

number = 150

Number of milliseconds that useResource will wait until changing state to loading. Pass skipLoadingFor: 0 if you want to see loading state immediatly after executing load function.

Returns

cancel

() => void

Cancels last running load function by calling abort() on Abort Controller signal passed within Config. Be aware that it will work only if you handle signal manually in your load, e.g. passing it into your fetch call.

reset

() => void

Cancles last running load function and sets resource into initial state.

resource

Resource<Data, Error>

Holds the state of load execution. To see what you can do with resource check @throned/resource-ts

run

(runParams?: Params = props.params) => Promise<Resource<Data, Error>>

Call run to execute load manually. By default it cancels previous load and uses params passed into props. You can disable auto-cancelling by passing cancellable: false into props and you can overwrite default params by providing runParams.

const {run} = useResource(load, {params: 42})
run() // load(42)
run(100) // load(100)

bindError

<BindedError>() => useResource<Params, Data, Error = BindedError>

Binds the Error type of useResource. It's handy in cases where you want to infer Params and Data from load function, but want to provide Error type explicitly.

class HttpError extends Error {
  /* */
}

const load = (): Promise<{username: string}> => {
  /* */
}

const useHttp = bindError<HttpError>()

const {resource} = useHttp(load)
resource // Resource<{ username: string }, HttpError>

createResource

(load: Load<Params, Data>) => (props: UseResourceProps) => useResource

Binds load function. Use it for creating reusable hook with the same load function.

createResourceWithError

<BindedError>() => (load: Load<Params, Data>) => (props: UseResourceProps) => useResource<Params, Data, Error = BindedError>

Binds error and load function. Use it for creating reusable hook with the same load function and explicit Error type.

Components

Use components to render the UI depending on Resource state.

You can provide of prop explicitly for each component.

const user = useResource(loadUser)
<div>
  <Match of={user.resource} states={['initial', 'loading']}>
    <p>Not ready yet</p>
  </Match>
  <Failure of={user.resource}>{error => /* */}</Failure>
  <Success of={user.resource}>{user => /* */}</Success>
</div>

But recommended way is to use getStateComponents to bind of prop.

const user = useResource(loadUser)
const State = getStateComponents(user.resource)
<div>
  <State.Match states={['initial', 'loading']}>
    <p>Not ready yet</p>
  </State.Match>
  <State.Failure>{error => /* */}</State.Failure>
  <State.Success>{user => /* */}</State.Success>
</div>

All components accepts render props and children (valid jsx or render function). If you provide both children and render function - render will take precedence.

Initial

type InitialProps = {
  children?: ReactNode | (() => ReactNode);
  of: AnyResource;
  render?: () => ReactNode;
}

Loading

type LoadingProps = {
  children?: ReactNode | (() => ReactNode);
  of: AnyResource;
  render?: () => ReactNode;
}

Success

type SuccessProps<D> = {
  children?: ReactNode | ((value: D) => ReactNode);
  of: Resource<D, unknown>;
  render?: (value: D) => ReactNode;
}

Failure

type FailureProps<E> = {
  children?: ReactNode | ((error: E) => ReactNode);
  of: Resource<unknown, E>;
  render?: (error: E) => ReactNode;
}

Match

type MatchProps<D, E> = {
  children?: ReactNode | ((resource: Resource<D, E>) => ReactNode);
  of: Resource<D, E>;
  render?: (resource: Resource<D, E>) => ReactNode;
  states: NotEmptyArray<Tag>;
}

getStateComponents

(of: Resource<D, E>) => { Initial, Loading, Success, Failure, Match }

Returns state components with binded of prop.

Guides

Todo.