Giter Club home page Giter Club logo

react-hook-thunk-reducer's Introduction

react-hook-thunk-reducer

Akin to redux-thunk, useThunkReducer() augments React's useReducer() hook so that the action dispatcher supports thunks. Now, you can write action creators that return a function rather than an action!

Requires React v16.8 and above.

Npm version Travis David


Install

npm install react-hook-thunk-reducer

Then just import it and use it like you would React.useReducer().

import { useThunkReducer } from 'react-hook-thunk-reducer';

function Component({ initialState }) {
  const [state, dispatch] = useThunkReducer(reducer, initialState);

  // ...
}

Usage

Create your actions just like you would in Redux. Similar to redux-thunk, if an action returns a function, it's treated as a thunk and has access to the current state.

function increment() {
  return {
    type: 'increment'
  };
}

function incrementIfOdd() {
  return (dispatch, getState) => {
    const { count } = getState();

    if (count % 2 !== 0) {
      dispatch(increment());
    }
  };
}

Create your functional component and call the useThunkReducer() hook as if it were React.useReducer();

import { useThunkReducer } from 'react-hook-thunk-reducer';

// ...

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    default:
      throw new Error();
  }
}

function Counter({ initialState }) {
  const [state, dispatch] = useThunkReducer(reducer, initialState);

  // ...

  return (
    <>
      Count: {state.count}
      <button onClick={onButtonPress}>+</button>
    </>
  );
}

Dispatch your actions using the augmented dispatch function.

const onButtonPress = () => {
  dispatch(incrementIfOdd());
};

The value of the inner function will be returned when dispatching thunks.

function incrementAndReturnCount() {
  return (dispatch, getState) => {
    dispatch(increment());

    return getState().count;
  };
}

const newCount = dispatch(incrementAndReturnCount());

react-hook-thunk-reducer's People

Contributors

chhsiao1981 avatar lewis500 avatar nathanbuchar avatar nutstick avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

react-hook-thunk-reducer's Issues

Support Promises

The Redux Dispatch will return a promise, allowing you to chain actions after the dispatch has taken place.

While the native useReducer dispatch does not return a promise, would it make sense for this Thunk implementation to do so?

Support middleware?

Hi Nathan, forgive me if I don’t understand the API perfectly, but as I understand it, the current implementation does not support adding custom middleware functions?

I think it would really add to the usefulness of this package. What do you think?

Expose getState

There are non-dispatch scenarios where you need to grab the current value of state and waiting for it to propagate through props or context is not appropriate (say in a "save" callback). Since useThunkReducer already creates getState internally to expose to thunk functions, it would be trivial to expose getState alongside the current state and dispatch.

Avoid react exhaustive deps error

Thanks for the small tool! To avoid infinite loop while using // eslint-disable-next-line react-hooks/exhaustive-deps, you should use useCallback, this will not recompute dispatch everytime and thus not trigger the effects that dispatch actions.

I changed a bit your code to do something like that :

export function useThunkReducer<S, A>(reducer: Reducer<S, A>, initialArg: S, init: (s: S) => S = s => s): [S, Dispatch<A | Thunk<S, A>>] {
    const [hookState, setHookState] = useState(init(initialArg));

    // State management.
    const state = useRef(hookState);
    const getState = useCallback(() => state.current, [])
    const setState = useCallback((newState) => {
        state.current = newState;
        setHookState(newState);
    },[]);

    // Reducer and augmented dispatcher.
    const reduce = useCallback((action) => reducer(getState(), action), [getState, reducer])
    const dispatch:Dispatch<A | Thunk<S, A>> = useCallback((action) => (
        typeof action === 'function'
            // @ts-ignore
            ? action(dispatch, getState)
            : setState(reduce(action))
    ), [getState, reduce, setState]);

    return [hookState, dispatch];
}

dist file is huge

The size of the file resulting from npm run-script build is 194kb.
This is also the case for the package on npmjs.org

I think React is bundled with the lib or something, is this the expected result?

[TS] Return type of `dispatch` when passing thunk action

Currently, dispatch doesn't carry forward return type of thunk action to return type of dispatch

import { useThunkReducer } from 'react-hook-thunk-reducer';

const thunkAction = () => {
  return (
    dispatch: ThunkDispatch<number, SetAction>,
    getState: () => number
  ): number => {
    return 0;
  };
};


dispatch(thunkAction()) // Expect `number`, but return `void`

The actual code itself already return the value

const dispatch = useCallback((action) => {
return typeof action === 'function'
? action(dispatch, getState)
: setState(reduce(action));
}, [getState, setState, reduce]);

This should cause by reusing Dispatch type from React that only return void

export default function useThunkReducer<S, A>(reducer: Reducer<S, A>, initialArg: S, init?: (s: S) => S): [S, Dispatch<A | Thunk<S, A>>]

`dispatch` is recreated on every state change

In the native React useReducer, the second element of the returned array (usually referred to as dispatch) is not recreated whenever the state changes, which means it can be used as an element of a hook's dependency array without causing unnecessary runs of that hook. The second element of the array returned by useThunkReducer, however, seems to regenerate on every state update.

Is there any way to change something so that the dispatch element always === itself?

Does not work as documented when installed from NPM.

I got the following error when following the instructions in the docs.

When I manually copied the hook from the src folder in the repo and imported that instead, it worked.

Line that failed:

const [state, dispatch] = useThunkReducer(reducer, initialState);

The error:

Uncaught TypeError: react_hook_thunk_reducer__WEBPACK_IMPORTED_MODULE_2___default is not a function or its return value is not iterable
    at myFile (myFile.js:8)
    at myFile2 (myFile.story.jsx:45)
    at renderWithHooks (react-dom.development.js:12939)
    at mountIndeterminateComponent (react-dom.development.js:15021)
    at beginWork (react-dom.development.js:15626)
    at performUnitOfWork (react-dom.development.js:19313)
    at workLoop (react-dom.development.js:19353)
    at HTMLUnknownElement.callCallback (react-dom.development.js:150)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:200)
    at invokeGuardedCallback (react-dom.development.js:257)

This package is incompatible with Server-side Rendering

When I build my server-side renderer bundle with webpack, it is broken by this package's module output type of amd. This is because AMD format involves exporting the module as a self-invoking function that passes a direct reference on window, resulting in the following error:

ReferenceError: window is not defined

combine redusers

Hi, first i want to say that it is very nice package. ty.
but could you explain how can i combine all my redusers, to unite all parts of state in one global state?
or maybe the idea is that i have only one reduser and one useThunkReducer?

Support injecting a custom argument

Redux-thunk has a feature where you can inject a custom argument.

I think this library can support the same feature if it were implemented like so:

helpers/useThunkReducer.js

import { withExtraArgument } from 'react-hook-thunk-reducer';

import BrowserApp from '../BrowserApp';

export default withExtraArgument({ app: new BrowserApp() });

An implementation of this might look like thus:

const saveData = (dispatch, getState, { app }) => {
  app.localStorage.setItem('data', JSON.stringify(data));
};

React peer dependency conflict

When using React 17, npm install react-hook-thunk-reducer will fail without forcing.

$ npm install react-hook-thunk-reducer
npm ERR! code ERESOLVE
npm ERR! ERESOLVE unable to resolve dependency tree
npm ERR! 
npm ERR! While resolving: [email protected]
npm ERR! Found: [email protected]
npm ERR! node_modules/react
npm ERR!   react@"^17.0.1" from the root project
npm ERR! 
npm ERR! Could not resolve dependency:
npm ERR! peer react@"^16.8.0" from [email protected]
npm ERR! node_modules/react-hook-thunk-reducer
npm ERR!   react-hook-thunk-reducer@"*" from the root project
npm ERR! 
npm ERR! Fix the upstream dependency conflict, or retry
npm ERR! this command with --force, or --legacy-peer-deps
npm ERR! to accept an incorrect (and potentially broken) dependency resolution.
npm ERR! 
npm ERR! See /Users/steph/.npm/eresolve-report.txt for a full report.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.