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

use-reducer-effect

v1.1.2

Published

A tiny library that enables side effects with the useReducer hook

Downloads

263

Readme

Build Coverage License Version Types Size Dependencies Pull Requests welcome Downloads semantic-release

Table of Contents

The Problem

You are using the useReducer hook to manage your state, but you need a way to perform side effects (like fetching data from an API or logging) without mixing those concern together.

The Solution

use-reducer-effect let's you define a second function next to the reducer function, where you can manage your side effects.

This way you can run your side effect logic on certain actions, while also allowing side effects to update the store by dispatching new actions.

Getting started

Install the library with

npm install --save use-reducer-effect

and import the hook into your code

import { useReducerWithSideEffects } from "use-reducer-effect";

If you already use a reducer to manage your state you will feel right at home with using them to manage side effects to.

useReducerWithSideEffects uses the same API as useReducer does, but gives you the ability to define a function which is called after your reducer function has run to run additional logic like fetching data from an API.

Defining the effect function

The effect function takes the same argument as the reducer function. state and action.

Instead of modifying the state, it is responsible for handling side effects like making http calls.

Let's assume we want to fetch from an API whenever an action called LOAD is dispatched. When the data is there, we want to feed it back into our reducer.

Note: The effect function will be called after the reducer has updated the state.

// define the reducer as usual
function reducer(state: State, action) {
  switch (action.type) {
    case ACTION_LOAD: // this action is dispatched by clicking on the button
      return { ...state, loading: true };
    case ACTION_LOAD_SUCCESSFUL: // this action is dispatched by the side effect. We'll learn how to do this in a minute.
      return { ...state, loading: false, data: action.payload };
  }

  return state;
}

// define the effect function which is executed after the reducer has run
async function effect(state, action) {
  switch (action.type) {
    case ACTION_LOAD:
      const response = await fetch(
        `https://api.github.com/users/${action.payload}/repos`
      );
      const data = await response.json();
      return {
        type: ACTION_LOAD_SUCCESSFUL,
        payload: data
      };
  }
}

// using the hook
const MyComponent = () => {
  const [state, dispatch] = useReducerWithSideEffects(reducer, effect);
};

Data Flow

Data flow visualization

  1. The action LOAD is dispatched with a payload (in this case the GitHub username)
  2. The reducer function is run and updated state is returned to the component
  3. The effect function is called, which has access to the updated state and the dispatched action (LOAD)
  4. The effect function triggers an http request
  5. It dispatches the action ACTION_LOAD_SUCCESSFUL with the API response data as payload
  6. The reducer function is called again (ACTION_LOAD_SUCCESSFUL) and updates the state
  7. The effect function is called again with the new state (API response) and the action ACTION_LOAD_SUCCESSFUL. We didn't register a side effect for this action so it doesn't do anything.

API

useReducerWithSideEffects(reducer, effect, initialValue?, init?)

The only difference between this function and useReducer is the effect function you need to provide as the second argument.

Effect Function

function(state, action) => Promise<action|undefined>

The effect function is called with the updated state and the action that caused the state update. It needs to return a Promise (async/await works great here) with either a action if you want to update the state again (i.e. after fetching from an API) or undefined if you do not want to update the state (i.e. if you want to use a side effect for logging purposes only)

Advanced

createSideEffectReducer

It is possible to use the higher order function createSideEffectReducer which takes the effect function as it's only argument to create a hook which provides you with the exact API signature that useReducer uses.

This way you can provide a nice abstraction for shared functionality like logging.

const useLoggingReducer = createSideEffectReducer(async (state, action) => {
  console.log("Action", action);
  console.log("Current State", state);
});

const MyComponent = () => {
  const [state, dispatch] = useLoggingReducer(reducer, {
    count: 0
  });
};

Examples

🔗 API Call

Use the effect function to handle data fetching from an API

🔗 Logging

Use createSideEffectReducer to create a useReducer like hook that logs all actions and state changes.

Acknowledgments

This library is greatly inspired by the idea of ngrx effects, which is an awesome library if your working with Angular.

Contributors