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

@aredant/use-query-manager

v2.0.1

Published

A fast and efficient library for making requests and manage state result in a global level, that give data access from all components of any level, using in React with cache and browser event superpowers. From version 2 was itroduced a custom global state

Downloads

380

Readme

React Use Query

A fast and efficient library for making requests and manage state result in a global level, that give data access from all components of any level, using in React with cache and browser event superpowers. From version 2 was itroduced a custom global state management system, check it out here.

npm version GitHub license Maintenance

New version of react use query library. Check on npm and github.

🎉 Version 2.0.x is live 🎉

Check out for changes in the CHANGELOG:

Changelog

Supporting the project

Maintaining a project takes time. To help allocate time, you can Buy Me a Coffee 😉

What is React Use Query?

Package to manage all types of queries, using useQuery(url<String>, options<QueryOptions>) hook, with cache control system and granular access to context state. It can be used to optimize all request process.

It is fast and don't make useless request thanks to cache control system. It can also give you access to context state everywhere in your app thanks to useQueryState(name) hook and <QueryProvider>.

If you need to trigger request just after an event like button click, in an efficient way, you should use useQueryEvent(url<String>, options<QueryOptions>) hook instead (example here).

Contents

  1. Install
  2. Get Started
  3. Options
  4. Returns
  5. Usage Examples
  6. Global state management

Install

Inside your project run on terminal:

npm i @aredant/use-query-manager

or

yarn add @aredant/use-query-manager

The only one dependency that will be installed is @aredant/use-query-manager.

Get Started

Import the package on your main file and wrap project inside QueryProvider.

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from "@aredant/use-query-manager"

import './index.css'

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider>
    <App />
  </QueryProvider>,
)

Options

Following the list of all avaiable options of useQuery hook:

| Name | Type | Description | |---------------------|:-------------------------------|:-----------------------------------------------------------------------------| | name | String | It should contains name string for context state granular control. | | selector | String | It should contains key value to select from result object. | | pick | Function or Array<String> | It rappresent the function or the array to pick just a portion of data. | | transform | Function | It rappresent the funcion to transform data before saving on state. | | method | String | It should be one of "GET", "POST", "PUT", "PATCH", "DELETE". | | headers | Object | Headers must be an object. It should contains request headers key value. | | body | Any | Request body data | | isDebuggerActivated | Boolean | It should be activated if you need to debug all process. | | cacheTimeout | Number | It rappresent the timeout to remove cached data from memory in milliseconds. |

Following the list of all avaiable options of useQueryEvent hook:

| Name | Type | Description | |---------------------|:-------------------------------|:-----------------------------------------------------------------------------| | name | String | It should contains name string for context state granular control. | | selector | String | It should contains key value to select from result object. | | pick | Function or Array<String> | It rappresent the function or the array to pick just a portion of data. | | transform | Function | It rappresent the funcion to transform data before saving on state. | | method | String | It should be one of "GET", "POST", "PUT", "PATCH", "DELETE". | | headers | Object | Headers must be an object. It should contains request headers key value. | | body | Any | Request body data | | isDebuggerActivated | Boolean | It should be activated if you need to debug all process. | | cacheTimeout | Number | It rappresent the timeout to remove cached data from memory in milliseconds. |

Returns

useQuery hook return an object with following keys:

| Name | Type | Description | |-----------|:------------------------------|:-----------------------------------------------------------------------------------------| | data | Any | Data returned from request | | error | Error or null | Request error. | | loading | Boolean | Request loading state. | | mutate | Function(data<ReactState>) | Mutate function to manipulate data state, available everywhere inside QueryProvider. | | refresh | Function | Data refresh function. | | cache | Object | Cache control function: get(url<String>), has(url<String>), clear() |

useQueryEvent hook return an object with following keys:

| Name | Type | Description | |-------------|:------------------------------|:-----------------------------------------------------------------------------------------| | sendRequest | Function | Trigger function to send request | | isSending | Boolean | State of sending status | | data | Any | Data returned from request | | error | Error or null | Request error. | | loading | Boolean | Request loading state. | | mutate | Function(data<ReactState>) | Mutate function to manipulate data state, available everywhere inside QueryProvider. | | refresh | Function | Data refresh function. | | cache | Object | Cache control function: get(url<String>), has(url<String>), clear() |

Usage Examples

Following usage example:

Basic

main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from "@aredant/use-query-manager"

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider>
    <App />
  </QueryProvider>,
)

App.jsx

import { useEffect } from 'react'
import { useQuery } from '@aredant/use-query-manager'

import InnerComponent from './InnerComponent'

const App = () => {
  const { data, error, loading, mutate, refresh, cache } = useQuery("https://dummyjson.com/products", {
    name: "products", // State name to select right context
    selector: "products", // Selector for first level request data
    method: "GET", // Request method
    headers: {}, // Request headers
    body: undefined, // Request body
    transform: (data) => { // Transform response data
      return data.filter((item) => item.id % 2 === 0);
    },
    pick: (key, value) => { // Pick a portion of data
      if (typeof value === "string" || key === "images") return undefined;
      return value;
    },
    cacheTimeout: 5000, // Timeout to auto-clear cache, 0 if you don't want to auto-clear cache
    isDebuggerActivated: true, // -> Take a look to the inspector console 
  });

  useEffect(() => {
    console.log(data, error, loading);
  }, [data, error, loading]);

  return (
    <>
      <pre>
        <InnerComponent />
      </pre>
    </>
  )
}

export default App

InnerComponent.js

import {useQueryState} from '@aredant/use-query-manager'

const InnerComponent = () => {
  const [data, setData] = useQueryState(); // Get all available query data
  const [products, setProducts] = useQueryState("products"); // Get just a portion of data by name

  return (
    <pre>
        {data && JSON.stringify(data, null, 2)}
        {products && JSON.stringify(products, null, 2)}
    </pre>
  )
}

export default InnerComponent;

Pagination

main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from "@aredant/use-query-manager"

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider>
    <App />
  </QueryProvider>,
)

App.jsx

import { useState, useEffect } from 'react'
import { useQuery } from '@aredant/use-query-manager'

const API_URL = "https://dummyjson.com/products";

const _formatSkip = (limit, page) => {
  return limit * (page - 1);
}

const App = () => {
  const [page, setLimit] = useState(1);
  const [limit, setPage] = useState(10);
  const [url, setUrl] = useState(`${API_URL}?limit=${limit}&skip=${_formatSkip(limit, page)}`);

  const { data: products, error, loading, mutate, refresh, cache } = useQuery(url, {
    name: "products", // State name to select right context
    selector: "products", // Selector for first level request data
    method: "GET", // Request method
    headers: {}, // Request headers
    body: undefined, // Request body
    transform: (data) => { // Transform response data
      return data.filter((item) => item.id % 2 === 0);
    },
    // pick: (key, value) => { // Pick a portion of data
    //   if (typeof value === "string" || key === "images") return undefined;
    //   return value;
    // },
    pick: ["id", "title", "description"], // Pick a portion of data using array of key name
    cacheTimeout: 5000, // Timeout to auto-clear cache, 0 if you don't want to auto-clear cache
    isDebuggerActivated: true, // -> Take a look to the inspector console 
  });

  const handlePrevPage = () => {
    if (page > 1) setPage((page) => page - 1);
  }
  
  const handleNextPage = () => {
    if (page < Math.ceil(products.length / limit)) setPage((page) => page + 1);
  }

  useEffect(() => {
    setUrl(`${API_URL}?limit=${limit}&skip=${_formatSkip(limit, page)}`);
  }, [page, limit]);

  return (
    <>
      <div>
        <button onClick={handlePrevPage}>Prev</button>
        <span>{page}</span>
        <button onClick={handleNextPage}>Next</button>
      </div>
      <table>
        <thead>
          <tr>
            <th>ID</th>
            <th>Title</th>
            <th>Description</th>
          </tr>
        </thead>
        <tbody>
          {
            products && products.map(({ id, title, description }) => (
              <tr key={id}>
                <td>{id}</td>
                <td>{title}</td>
                <td>{description}</td>
              </tr>
            ))
          }
        </tbody>
      </table>
    </>
  )
}

export default App

Request on event

If you want to trigger the request on event like click you can use useQueryEvent hook. Check the following example:

main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from "@aredant/use-query-manager"

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider>
    <App />
  </QueryProvider>,
)

App.jsx

import { useEffect, useState } from 'react';
import { useQueryState, useQueryEvent } from './hooks';

import "./App.css";

const App = () => {
  const [id, setId] = useState(1);
  const [url, setUrl] = useState(`https://dummyjson.com/products/${id}`);

  const { sendRequest, isSending, data, error, loading, refresh } = useQueryEvent(url, {
    name: "product",
    isDebuggerActivated: true
  });

  useEffect(() => {
    setUrl(`https://dummyjson.com/products/${id}`);
  }, [id])

  return (
    <>
      <div>
        <input type="text" value={id} onInput={({ target }) => setId(target.value)} />
        <button onClick={sendRequest} disabled={isSending}>Send Request</button>
      </div>
      <div>
        {
          loading ? (
            <p>Loading...</p>
          )
          :
          error ? (
            <p>{error.message}</p>
          )
          :
          (
            <pre>
              {
                data && JSON.stringify(data, null, 2)
              }
            </pre>
          )
        }
      </div>
    </>
  )
}

export default App

Of course you can use a combination of useQuery and useQueryEvent inside the same component.

Using selector

main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from "@aredant/use-query-manager"

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider>
    <App />
  </QueryProvider>,
)

App.jsx

import { useEffect } from 'react'
import { useQuery } from '@aredant/use-query-manager'

import InnerComponent from './InnerComponent'

const App = () => {
  const { data, error, loading, mutate, refresh, cache } = useQuery("https://dummyjson.com/products", {
    name: "products", // State name to select right context
    selector: "products", // Selector for first level request data
    method: "GET", // Request method
    headers: {}, // Request headers
    body: undefined, // Request body
    transform: (data) => { // Transform response data
      return data.filter((item) => item.id % 2 === 0);
    },
    pick: (key, value) => { // Pick a portion of data
      if (typeof value === "string" || key === "images") return undefined;
      return value;
    },
    cacheTimeout: 5000, // Timeout to auto-clear cache, 0 if you don't want to auto-clear cache
    isDebuggerActivated: true, // -> Take a look to the inspector console 
  });

  useEffect(() => {
    console.log(data, error, loading);
  }, [data, error, loading]);

  return (
    <>
      <pre>
        <InnerComponent />
      </pre>
    </>
  )
}

export default App

InnerComponent.js

import { useQuerySelector } from '@aredant/use-query-manager'

const InnerComponent = () => {
  const products = useQuerySelector((state) => state.products); // Get just a portion of data by name using query selector callback function

  return (
    <pre>
        {products && JSON.stringify(products, null, 2)}
    </pre>
  )
}

export default InnerComponent;

Global state management

From version 2.0.0 is available a fully featured global state management system.

Work with global State

First of all you need to setup a store using createQueryStore and all dispatchers usign createDispatcher and pass them to QueryProvider as follow:

store.js

import { createQueryStore } from '@aredant/use-query-manager'

export default createQueryStore({
  auth: { // !IMPORTANT Must match with dispatcher name
    token: null,
    user: null,
  }
});

dispatchers/authDispatcher.js

import { createQueryDispatcher } from '@aredant/use-query-manager'

export default createQueryDispatcher({
  name: "auth", // !IMPORTANT Must match with store key object name
  actions: {
    login: (state, payload) => {
      state.token = payload.token;
      state.user = payload.user;
    },
    logout: (state) => {
      state.token = null;
      state.user = null;
    }
  }
});

main.jsx

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'

import { QueryProvider } from '@aredant/use-query-manager'

import store from './store'
import authDispatcher from './dispatchers/authDispatcher'

import './index.css'

const dispatchers = [
  authDispatcher,
]

ReactDOM.createRoot(document.getElementById('root')).render(
  <QueryProvider store={store} dispatchers={dispatchers}>
    <App />
  </QueryProvider>,
)

Then you can use dispatcher inside any component of your app.

App.jsx

import { useQueryState, useQuerySelector, useQueryDispatcher } from '@aredant/use-query-manager';

import "./App.css";

const App = () => {
  const [data, setData] = useQueryState("auth");

  const auth = useQuerySelector(({ auth }) => auth);
  const { login, logout } = useQueryDispatcher("auth");

  return (
    <>
      <div>
        <p>Token: {auth.token}</p>
        <p>User: {auth.user}</p>
        <button onClick={() => login({ token: "1234abcd", user: "Alex" })}>Login</button>
        <button onClick={() => logout()}>Logout</button>
      </div>
      <div className="container">
        <pre>
            // ====================== <br />
            // -------- DATA -------- <br />
            // ======================
            <br />
            <br />
            {data && JSON.stringify(data, null, 2)}
        </pre>
      </div>
    </>
  )
}

export default App