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

react-network-query

v0.2.8

Published

Declarative components for making network requests in react

Downloads

42

Readme

React Network Query

npm version

React Network Query is a library inspired by React Apollo. Do you know how React Appolo allows simple declarative React components to make GraphQL requests and save the state? This library does something similar, but for REST calls. Think of it as the React Apollo for REST requests.

It works out of the box for React and ReactDOM.

There is support for React Native, but it is still experimental.

Installation

npm install react-network-query --save
# or using yarn
yarn add react-network-query

Usage

To get started you will need to add a <NetworkQueryProvider/> component to the root of your React component tree. This component provides context functionality to all the other components in the application without passing it explicitly:

import { NetworkQueryProvider } from 'react-network-query'

ReactDOM.render(
  <NetworkQueryProvider url="http://api.dev">
    <MyRootComponent />
  </NetworkQueryProvider>,
  document.getElementById('root'),
)

Now you may create <Query> and <Mutation> components in this React tree that are able to make REST network calls and save the response as a state.

Connect one of your components to your REST server using the <Query> component:

import { Query } from 'react-network-query'

const Cats = () => (
  <Query endpoint="/cats">
    {({ data, isLoading, loadMore, error, refetch }) => {
      if (isLoading) {
        return <span>Loading...</span>
      }

      if (error) {
        return <span>Something went wrong</span>
      }

      return (
        <ul>
          {data.map((cat) => (
            <li key={cat.id}>{cat.name}</li>
          ))}
        </ul>
      )
    }
  </Query>
)

If you render <Cats /> within your component tree, you will first see a loading state, and then a list of cat names once React Network Query finishes to load data from your API.

Use the <Mutation> component to make an update REST request, with one of the POST | PUT | PATCH | DELETE methods, and wrap your React elements that trigger the update:

import { Mutation } from 'react-network-query'

const CatsContainer = () => (
  <>
    <Cats />
    <Mutation endpoint="/cats/create" method="POST" body={{ name: 'Cate' }}>
      {({ update, isMutating }) => (
        <button onClick={() => update()}>
          {isMutating ? 'Creating...' : 'Create new cat'}
        </button>
      )}
    </Mutation>
  </>
)

Or you can pass parameters directly to the update function:

import { Mutation } from 'react-network-query'

const CatsContainer = () => (
  <>
    <Cats />
    <Mutation>
      {({ update, isMutating }) => (
        <button
          onClick={
            () => update({
              endpoint: '/cats/create',
              method="POST"
              body={{ name: 'Cate' }}
            })
          }
        >
          {isMutating ? 'Creating...' : 'Create new cat'}
        </button>
      )}
    </Mutation>
  </>
)

In the example above, if you render <CatsContainer /> within your component tree and the user clicks on the button to add a new cat, you will see a loading state, until the REST update call finishes.

Passing parameters directly to the update function will overwrite any corresponding props passed to the <Mutation /> component.

If you would like to see all the features that <NetworkQueryProvider />, <Query /> and <Mutation /> support be sure to check out the API reference.

Usage with hooks

If you prefer to use hooks with React Network Query, there are two main exposed functions:

  • useQuery
  • useMutation

Please note that the components which will use the above hook functions need to be wrapped inside <NetworkQueryProvider />.

import { useQuery } from 'react-network-query'

const Cats = () => {
  const { data, query, isLoading, error, refetch, loadMore, isLoadingMore } = useQuery({
    endpoint: '/cats?_page={{page}}&_limit={{limit}}',
    variables: {
      limit: 20
      page: 0,
    },
  })

  // load cats data on mount
  useEffect(() => {
    query()
  }, [])

  if (isLoading) {
    return <span>Loading...</span>
  }

  if (error) {
    return <span>Something went wront.</span>
  }

  return (
    <>
      <ul>
        {data.map(cat => <li key={cat.id}>{cat.name}</li>)}
      </ul>
      <button
        onClick={
          () => loadMore(
            '/cats?_page={{page}}&_limit={{limit}}',
            { limit: 20, page: 1 }
          )
        }
      >
        Load more cats
      </button>
      {isLoadingMore && (<span>Loading more cats...</span>)}
      <button onClick={() => refetch()}>
        Refetch cats
      </button>
    </>
  )
}

If you render <Cats /> within your component tree, the cats will be fetched from the API when the component will mount, it has the same functionality as the <Query /> component.

You can control when the actual initial fetch takes place using the query function exposed by the useQuery hook. The useQuery interface is virtually the same as the <Query /> component one.

For making a POST | PUT | PATCH | DELETE network call you can use the useMutation hook:

import { useMutation } from 'react-network-query'

const CatsContainer = () => {
  const { update, isMutating, error } = useMutation({
    endpoint: '/cats',
    method: 'POST',
  })

  return (
    <>
      <Cats />
      <button onClick={() => update({ body: { name: 'Mr. Whiskers' } })}>
        {isMutating ? 'Loading...' : 'Create cat'}
      </button>
      {error && <span>Something went wrong</span>}
    </>
  )
}

If you render <CatsContainer /> within your component tree, when the user will click the Create cat button a new POST network request will be made, which will create a new cat.

The useMutation interface is virtually the same as the <Mutation /> component.

Local state update

To update the local state without making a network call, or to reflect certain local changes in the UI use setData function. It receives the update piece of the data for that specific endpoint:

import { Query } from 'react-network-query'

const Cats = () => (
  <Query endpoint="/cats">
    {({ data, setData }) => (
      <>
        <ul>
          {data.map(cat => (
            <li key={cat.id}>{cat.name}</li>
          ))}
        </ul>
        <button
          onClick={() => {
            const updatedCats = data.map(cat => ({
              ...cat,
              food: 'whiskas',
            }))

            setData(updatedCats)
          }}
        >
          Add food
        </button>
      </>
    )}
  </Query>
)

or using a hook:

import { useQuery } from 'react-network-query'

const Cats = () => {
  const { data = [], query, setData } = useQuery({ endpoint: '/cats' })

  return (
    <>
      <ul>
        {data.map(cat => (
          <li key={cat.id}>{cat.name}</li>
        ))}
      </ul>
      <button
        onClick={() => {
          const updatedCats = data.map(cat => ({
            ...cat,
            food: 'whiskas',
          }))

          setData(updatedCats)
        }}
      >
        Add food
      </button>
      <button onClick={() => query()}>Fetch cats</button>
    </>
  )
}

Consume local state

We discourage the use of the <Consumer /> component and useConsumer hook, we recommend using specific <Query /> components and separating your application concerns.

For some specific edge cases you may require to get or set local data exposed by the NetworkQueryProvider in order to do this you can use the exposed <Consumer /> component or the useConsumer hook which exposes all of the data from the context, and the global setData function. This function does not do any queries nor it mutates data through network calls in any way:

import { Consumer } from 'react-network-query'

const EdgeCaseComponent = () => (
  <Consumer>
    {({ data, setData }) => (
      <>
        <span>{JSON.stringify(data)}</span>
        <button
          onClick={() => {
            setData({ '/cats': [] }) // this will rewrite the whole global state context
          }}
        >
          Set global state
        </button>
      </>
    )}
  </Consumer>
)

or using a hook:

import { useConsumer } from 'react-network-query'

const EdgeCaseComponent = () => {
  const [data, setData] = useConsumer()

  return (
    <>
      <span>{JSON.stringify(data)}</span>
      <button
        onClick={() => {
          setData({ '/cats': [] }) // this will rewrite the whole global state context
        }}
      >
        Set global state
      </button>
    </>
  )
}

Use a custom requester

If you need to use a custom requester for network requests please refer to the CUSTOM_REQUESTER documentation for an example on how you can write your own.

API Reference

<NetworkQueryProvider />

| Prop | Default | Type | Description | | :---------------------- | :-----: | :-------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | children | - | ReactElement | Required prop, element(s) that will be wrapped into React Network Query context. | | url? | - | string | Base URL used to construct all of the endpoints, this can be overwritten and extended by each <Query /> component with the endpoint prop. | | requester? | fetch | fetch or AxiosInstance or AxiosStatic | Request function to make all of the network calls with, by default window.fetch is used. We strongly recommend using axios instead. If you want to pass a custom request function, you will have to wrap it in a similar interface axios and fetch uses. | | persistentStorage? | - | PersistentStorage | A storage interface used for persistent saving of data. When it is passed data will be automatically persisted into the specified storage. It works out of the box with window.localStorage. For a custom persistent storage interface you will have to rewire it to be compliant with PersistentStorage | | clearPersistentStorage? | false | boolean | If passed as true the persistent storage will be cleared on Provider's initialization, works only if persistentStorage? prop has been passed as well. | | storageAsync? | false | boolean | Pass true if the persistent storage interface you are using works asynchronously (with promises). |

<Query />

| Prop | Default | Type | Description | | :-------------- | :-----: | :---------------------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | children | - | (arg0: QueryRenderArg) => ReactElement | Required prop, needs to be a function that will return a valid react element. | | endpoint | - | string | Required prop, the endpoint for which to make the network call. It will be concatenated to the url prop passed to the <NetworkQueryProvider /> if any. In case the endpoint is a valid url by itself e.g. https://local.dev/cats it will disregard the base url prop overall. | | variables? | - | { [key: string]: string or number } | key -> value pairs, used for interpolating the endpoint using moustache.js like handlebars syntax e.g. for /cats/{{id}} endpoint a { id: 2 } variables object can be passed. | | fetchOptions? | - | { [key: string]: string or number or object } | Additional options to be attached to the network request. The provided options depend on the requester instance used, so please consult axios/fetch api reference accordingly. | | onComplete? | - | (arg0: any) => void | Callback triggered when the network call is finished, it receives the returned network request data as a parameter on success and the Error instance in case of failure. | | refetchOnMount? | false | boolean | If passed as true it will do the request for the specified endpoint prop, even if data has already been fetched and it is saved in the state manager. |

<Mutation />

| Prop | Default | Type | Description | | :------------ | :-----: | :---------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | children | - | ({ update, isMutating, error }: { update: UpdateArg, isMutation: boolean, error: Error }) => ReactElement | Required prop, needs to be a function that will return a valid react element. It provides an update function to do the network request and an isMutating state for showing the current status of the network request. | | refetch? | - | boolean or string[] | If provided as true, it will trigger a refetch for all <Query /> components rendered in the current tree. It can receive a list of endpoints instead of a boolean value, in this case, it will trigger the refetch only for those <Query /> components that have the exact provided endpoint as prop. | | onComplete? | - | (arg0: any) => void | Callback triggered when the network call is finished, it receives the returned network request data as a parameter on success, and Error instance in case of failure. | | fetchOptions? | - | { [key: string]: string or number or object } | Additional options to be attached to the network request. The provided options depend on the requester instance used, so please consult axios/fetch api reference accordingly. |

The <Mutation /> component also inherits all UpdateArg Interface. The arguments used by the update function will always overwrite those ones passed directly as props to the <Mutation /> component.

UpdateArg Interface

| Prop | Type | Description | | :--------- | :-----------------------------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | endpoint? | string | The endpoint for which to make the network call, it will be concatenated to the url prop passed to <NetworkQueryProvider /> if any. In case the endpoint is a valid url by itself e.g. https://local.dev/cats it will disregard the base url overall. | | variables? | { [key: string]: string or number } | key -> value pairs, for interpolating the endpoint using moustache.js like handlebars syntax e.g. for /cats/{{id}} endpoint an { id: 2 } variables object can be passed. | | method? | POST or PUT or DELETE or PATCH | Network method for which the call should be made for. | | body? | { [key: string]: any } | The network request body. |

QueryRenderArg Interface

| Prop | Type | Description | | :------------ | :-----------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | data | any | The data returned by the rest network api call. | | isLoading | boolean | State of the very first network request, triggered on component mount. | | error | Error | The returned Error instance in case of network failure. | | refetch | () => Promise<any> | Refetches the data, useful for triggering refreshes. | | loadMore | (endpoint: string, variables?: { [key: string]: string or number }) => Promise<any> | Function used for loading more data, useful on paginations, the first parameter is the endpoint for which to make the network call, and the second parameter is variables object used for interpolating the endpoint string. | | isLoadingMore | boolean | State of the network request triggered by loadMore function. | | setData | (arg0: any[] | object) => void | An exposed function for updating localy the state data for a specific Query, this can be used for optimistic updates. |

PeristentStorage Interface

| Prop | Type | Description | | :--------- | :---------------------------------: | :----------------------------------------------------------------------- | | setItem | (key: string, value: any) => void | Function for setting a single key -> value pair into persistent storage. | | getItem | (key: string) => any | Function for retrieving data for a specific key from persistent storage. | | removeItem | (key: string) => void | Function for deleting data for a specific key from persistent storage. |

<Consumer />

| Prop | Default | Type | Description | | :------- | :-----: | :-------------------------------------------------------------------------------: | :---------------------------------------------------------------------------- | | children | - | (arg0: { data: any[] or object, setData: (arg0: any) => void }) => ReactElement | Required prop, needs to be a function that will return a valid react element. |

Examples

React Web