Redux Query React Integration

3.6.1-rc.2 · active · verified Sun Apr 19

redux-query-react provides the React-specific interface for integrating with redux-query, a library designed for managing network state within Redux applications. It streamlines the process of fetching data, handling optimistic updates, and managing cancellations directly from React components. The current stable release candidate is `3.6.1-rc.2`, indicating active development with ongoing release candidates. While a precise release cadence isn't specified, the project exhibits a feature-driven release model. Key differentiators include its adherence to core Redux principles (middleware, actions, selectors, reducers), ensuring minimal 'magic' and high extensibility, allowing for custom middleware, UI integrations, and network interfaces. It offers both modern React hooks (like `useRequest`, `useMutation`) and higher-order components (`connectRequest`) to colocate data dependencies with components and trigger requests on mount or update, working seamlessly with both functional and class components.

Common errors

Warnings

Install

Imports

Quickstart

This example demonstrates how to set up a Redux store with `redux-query`, define a `networkHandler` (mocked here), and use `redux-query-react`'s `useRequest` hook to fetch and display user data, along with `useMutation` for optimistic updates on a user's name.

import React from 'react';
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';
import { queriesReducer, queriesMiddleware, QueryConfig } from 'redux-query';
import { useRequest, useMutation } from 'redux-query-react';
import { createNetworkHandler } from 'redux-query-interface-superagent'; // For a real app, install this

// A mock network handler for demonstration purposes
const mockNetworkHandler = createNetworkHandler({
  adapter: (config) => {
    console.log('Mock API call:', config.url, config.method, config.body);
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (config.url === '/api/users/1') {
          resolve({
            status: 200,
            body: { id: 1, name: 'Alice', email: 'alice@example.com' },
            headers: new Headers(),
          });
        } else if (config.url === '/api/users/1' && config.method === 'PUT') {
          resolve({
            status: 200,
            body: { id: 1, name: config.body.name, email: 'alice@example.com' },
            headers: new Headers(),
          });
        } else {
          reject({ status: 404, body: 'Not Found', headers: new Headers() });
        }
      }, 500);
    });
  }
});

// Setup Redux store with redux-query
const rootReducer = combineReducers({
  queries: queriesReducer,
  // Add other reducers here
});

const store = createStore(
  rootReducer,
  applyMiddleware(queriesMiddleware(mockNetworkHandler))
);

interface User {
  id: number;
  name: string;
  email: string;
}

// Define a query config for fetching a user
const getUserQuery: QueryConfig = {
  url: '/api/users/1',
  update: {
    entities: (prevEntities: any = {}, newEntities: any) => ({
      ...prevEntities,
      user: newEntities.user, // Assuming API returns { user: { ... } }
    }),
  },
  // Map the query response data to a specific key, if needed.
  // data: (queryState) => queryState.entities.user
};

const UserProfile: React.FC = () => {
  // Use useRequest to fetch user data
  const { isPending, isFinished, data } = useRequest<User>(getUserQuery);

  // Use useMutation to update user data with optimistic updates
  const [updateUserName, { isPending: isUpdatingName }] = useMutation(
    (newName: string) => ({
      url: '/api/users/1',
      method: 'PUT',
      body: { name: newName },
      update: {
        entities: (prevEntities: any = {}, newEntities: any) => ({
          ...prevEntities,
          user: newEntities.user,
        }),
      },
      optimistic: {
        entities: (prevEntities: any = {}) => ({
          ...prevEntities,
          user: { ...prevEntities.user, name: newName + ' (optimistic)' },
        }),
      },
    })
  );

  const handleRenameUser = () => {
    updateUserName('Bob');
  };

  if (isPending) return <div>Loading user profile...</div>;
  if (!data) return <div>No user data available.</div>;

  return (
    <div>
      <h2>User Profile</h2>
      <p>ID: {data.id}</p>
      <p>Name: {data.name} {isUpdatingName && '(Updating...)'}</p>
      <p>Email: {data.email}</p>
      <button onClick={handleRenameUser} disabled={isUpdatingName}>Rename to Bob</button>
    </div>
  );
};

const App: React.FC = () => (
  <Provider store={store}>
    <UserProfile />
  </Provider>
);

export default App;

view raw JSON →