All Projects → conorhastings → Use Reducer With Side Effects

conorhastings / Use Reducer With Side Effects

Licence: mit

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Use Reducer With Side Effects

react-stateful-component
Functional stateful React components with sideEffect support
Stars: ✭ 19 (-74.67%)
Mutual labels:  reducer
Redux Machine
A tiny library (12 lines) for creating state machines in Redux apps
Stars: ✭ 338 (+350.67%)
Mutual labels:  reducer
Async Reduce
Reducer for similar simultaneously coroutines
Stars: ✭ 17 (-77.33%)
Mutual labels:  reducer
k-redux-factory
Factory of Redux reducers and their associated actions and selectors.
Stars: ✭ 18 (-76%)
Mutual labels:  reducer
Redux Orm
A small, simple and immutable ORM to manage relational data in your Redux store.
Stars: ✭ 2,922 (+3796%)
Mutual labels:  reducer
Reductor
Redux for Android. Predictable state container library for Java/Android
Stars: ✭ 460 (+513.33%)
Mutual labels:  reducer
coredux
Dualism to Redux. Two-way combining of redux modules
Stars: ✭ 14 (-81.33%)
Mutual labels:  reducer
Reapex
A lightweight framework to build pluggable and extendable redux/react application
Stars: ✭ 58 (-22.67%)
Mutual labels:  reducer
Swiftrex
Swift + Redux + (Combine|RxSwift|ReactiveSwift) -> SwiftRex
Stars: ✭ 267 (+256%)
Mutual labels:  reducer
Useeffectreducer
useReducer + useEffect = useEffectReducer
Stars: ✭ 642 (+756%)
Mutual labels:  reducer
pquery
pquery is an open-source (GPLv2 licensed) multi-threaded test program, written in C++, created to stress test the MySQL server (in any flavor), either randomly or sequentially, for QA purposes.
Stars: ✭ 48 (-36%)
Mutual labels:  reducer
React Recomponent
🥫 Reason-style reducer components for React using ES6 classes.
Stars: ✭ 272 (+262.67%)
Mutual labels:  reducer
Repatch
Dispatch reducers
Stars: ✭ 516 (+588%)
Mutual labels:  reducer
reducer-tester
Utilities for testing redux reducers
Stars: ✭ 19 (-74.67%)
Mutual labels:  reducer
Puddles
Tiny vdom app framework. Pure Redux. No boilerplate.
Stars: ✭ 24 (-68%)
Mutual labels:  reducer
cra-redux-boilerplate
⚛️🔨create-react-app application with redux and another cool libraries to make your life easier.
Stars: ✭ 15 (-80%)
Mutual labels:  reducer
Immer
Create the next immutable state by mutating the current one
Stars: ✭ 21,756 (+28908%)
Mutual labels:  reducer
Use Reducer X
🔩 An alternative to useReducer that accepts middlewares.
Stars: ✭ 62 (-17.33%)
Mutual labels:  reducer
Redux Dynamic Modules
Modularize Redux by dynamically loading reducers and middlewares.
Stars: ✭ 874 (+1065.33%)
Mutual labels:  reducer
Redux Ecosystem Links
A categorized list of Redux-related addons, libraries, and utilities
Stars: ✭ 5,076 (+6668%)
Mutual labels:  reducer

Use Reducer With Side Effects

Actions Status npm version

React's useReducer hook should be given a reducer that is a pure function with no side effects. (useReducer might call the reducer more than once with the same initial state.) Sometimes, however, it makes sense to include network calls or other side effects within the reducer in order to keep your program logic all in one place.

Inspired by the reducerComponent of ReasonReact, this library provides a way to declaratively declare side effects with updates, or to execute a side effect through the reducer while keeping the reducer pure. The general idea being that the side effects simply declare intent to execute further code, but belong with the update. reducers always return one of Update, NoUpdate, UpdateWithSideEffects, or SideEffects function.

One example in which this may be useful is when dispatching a second action depends on the success of the first action, instead of waiting to find out, one can declare the side effect along side the update.

Install

  • npm install use-reducer-with-side-effects
  • yarn add use-reducer-with-side-effects

Exports

  • Update - Return synchronous new state wrapped in this function for a plain update. Update(newState)
  • NoUpdate - Indicate that there are no changes and no side effects. NoUpdate()
  • SideEffect - Receives a callback function with state, and dispatch as arguments. SideEffect((state, dispatch) => { /* do something */ }
  • UpdateWithSideEffect - Very similar to Update and SideEffect combined. It takes the updated state as the first argument (as Update) and a side-effect callback as the second argument (as SideEffect). The callback function receives the updated state (newState) and a dispatch. UpdateWithSideEffect(newState, (state, dispatch) => { /* do something */ })

Default Export - useReducerWithSideEffects hook;

Nearly direct replacement to React's useReducer hook, however, the provided reducer must return the result of one of the above functions (Update/NoUpdate/UpdateWithSideEffects/SideEffects) instead of an updated object. See the useReducer documentation for different options on how to define the initial state.

const [state, dispatch] = useReducerWithSideEffects(reducer, initialState, init)

const [state, dispatch] = useReducerWithSideEffects(reducer, {})

Modify Existing Reducer

If you've got an existing reducer that works with React's useReducer and you want to modify to use this library, do the following:

  1. Modify every state change return to use Update.

    old: return {...state, foo: 'bar'}

    new: return Update({...state, foo: 'bar'}

  2. Modify every unchanged state return to use NoUpdate.

    old: return state

    new: return NoUpdate()

Now the reducer may be used with useReducerWithSideEffects and can have side effects added by using the SideEffect or UpdateWithSideEffect methods.

Example

Code Sandbox

A comparison using an adhoc use effect versus this library

adhoc
import React, { useReducer } from 'react';

function Avatar({ userName }) {
  const [state, dispatch] = useReducer(
    (state, action) => {
      switch (action.type) {
        case FETCH_AVATAR: {
          return { ...state, fetchingAvatar: true };
        }
        case FETCH_AVATAR_SUCCESS: {
          return { ...state, fetchingAvatar: false, avatar: action.avatar };
        }
        case FETCH_AVATAR_FAILURE: {
          return { ...state, fetchingAvatar: false };
        }
      }
    },
    { avatar: null }
  );

  useEffect(() => {
    dispatch({ type: FETCH_AVATAR });
    fetch(`/avatar/${userName}`).then(
      avatar => dispatch({ type: FETCH_AVATAR_SUCCESS, avatar }),
      dispatch({ type: FETCH_AVATAR_FAILURE })
    );
  }, [userName]);

  return <img src={!state.fetchingAvatar && state.avatar ? state.avatar : DEFAULT_AVATAR} />
}

Library with colocated async action

import useReducerWithSideEffects, { UpdateWithSideEffect, Update } from 'use-reducer-with-side-effects';

function Avatar({ userName }) {
  const [{ fetchingAvatar, avatar }, dispatch] = useReducerWithSideEffects(
    (state, action) => {
      switch (action.type) {
        case FETCH_AVATAR: {
          return UpdateWithSideEffect({ ...state, fetchingAvatar: true }, (state, dispatch) => { // the second argument can also be an array of side effects
                fetch(`/avatar/${userName}`).then(
                  avatar =>
                    dispatch({
                      type: FETCH_AVATAR_SUCCESS,
                      avatar
                    }),
                  dispatch({ type: FETCH_AVATAR_FAILURE })
                );
          });
        }
        case FETCH_AVATAR_SUCCESS: {
          return Update({ ...state, fetchingAvatar: false, avatar: action.avatar });
        }
        case FETCH_AVATAR_FAILURE: {
          return Update({ ...state, fetchingAvatar: false })
        }
      }
    },
    { avatar: null }
  );

  useEffect(() => dispatch({ type: FETCH_AVATAR }) , [userName]);

  return <img src={!fetchingAvatar && avatar ? avatar : DEFAULT_AVATAR} />;
}
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].