logo

redux-requests

Declarative AJAX requests and automatic network state management for single-page applications

showcase gif
[object Object]

Just actions

Just dispatch actions and enjoy automatic AJAX requests and network state management

[object Object]

First class aborts support

Automatic and configurable requests aborts, which increases performance and prevents race condition bugs before they even happen

[object Object]

Drivers driven

Compatible with anything for server communication. Axios, Fetch API, GraphQL, promise libraries, mocking? No problem! You can also integrate it with other ways by writing a custom driver!

[object Object]

Batch requests

Define multiple requests in single action

[object Object]

Optimistic updates

Update remote data before receiving server response to improve perceived performance

[object Object]

Cache

Cache server response forever or for a defined time period to decrease amount of network calls

[object Object]

Data normalisation

Use automatic data normalisation in GraphQL Apollo fashion, but for anything, including REST!

[object Object]

Server side rendering

Configure SSR totally on Redux level and write truly universal code between client and server

[object Object]

React bindings

Use react bindings to decrease code amount with React even more

With redux-requests, assuming you use axios (you could use it with anything else too!) you could refactor a code in the following way:

import axios from 'axios';
- import thunk from 'redux-thunk';
+ import { handleRequests } from '@redux-requests/core';
+ import { createDriver } from '@redux-requests/axios'; // or another driver
const FETCH_BOOKS = 'FETCH_BOOKS';
- const FETCH_BOOKS_SUCCESS = 'FETCH_BOOKS_SUCCESS';
- const FETCH_BOOKS_ERROR = 'FETCH_BOOKS_ERROR';
-
- const fetchBooksRequest = () => ({ type: FETCH_BOOKS });
- const fetchBooksSuccess = data => ({ type: FETCH_BOOKS_SUCCESS, data });
- const fetchBooksError = error => ({ type: FETCH_BOOKS_ERROR, error });
- const fetchBooks = () => dispatch => {
- dispatch(fetchBooksRequest());
-
- return axios.get('/books').then(response => {
- dispatch(fetchBooksSuccess(response.data));
- return response;
- }).catch(error => {
- dispatch(fetchBooksError(error));
- throw error;
- });
- }
+ const fetchBooks = () => ({
+ type: FETCH_BOOKS,
+ request: {
+ url: '/books',
+ // you can put here other Axios config attributes, like method, data, headers etc.
+ },
+ });
- const defaultState = {
- data: null,
- pending: 0, // number of pending FETCH_BOOKS requests
- error: null,
- };
-
- const booksReducer = (state = defaultState, action) => {
- switch (action.type) {
- case FETCH_BOOKS:
- return { ...defaultState, pending: state.pending + 1 };
- case FETCH_BOOKS_SUCCESS:
- return { ...defaultState, data: action.data, pending: state.pending - 1 };
- case FETCH_BOOKS_ERROR:
- return { ...defaultState, error: action.error, pending: state.pending - 1 };
- default:
- return state;
- }
- };
const configureStore = () => {
+ const { requestsReducer, requestsMiddleware } = handleRequests({
+ driver: createDriver(axios),
+ });
+
const reducers = combineReducers({
- books: booksReducer,
+ requests: requestsReducer,
});
const store = createStore(
reducers,
- applyMiddleware(thunk),
+ applyMiddleware(...requestsMiddleware),
);
return store;
};

Would you like to learn more?