javascriptreactjsreduxredux-saga

React hooks: dispatch action from useEffect


My folder structure:

|--App
  |--Components
    |--PageA.js
    |--PageB.js
    |--PageC.js
  |--common-effects
    |--useFetching.js

I am refactoring my code to fetch data from API, using react hooks. I want to dispatch an action from useEffect in useFetching.js that is intercepted by saga middleware. The action should be dispatched only when the components(PageA, PageB, PageC) mount.

I am using redux, react-redux and redux-saga.

PageA.js:

function(props) {
  useFetching(actionParams)
  //....//
}

Similar code for PageB and PageC components.

I have abstracted the reusable code to fetch data in useFetching Custom hook.

useFetching.js

const useFetching = actionArgs => {
  useEffect( () => {
    store.dispatch(action(actionArgs)); // does not work
  })
}

I don't know how to access redux dispatch in useFetching. I tried it with useReducer effect, but the sagas missed the action.


Solution

  • You would need to pass either bound action creators or a reference to dispatch to your hook. These would come from a connected component, same as you would normally use React-Redux:

    function MyComponent(props) {
        useFetching(props.fetchSomething);
    
        return <div>Doing some fetching!</div>
    }
    
    const mapDispatch = {
        fetchSomething
    };
    
    export default connect(null, mapDispatch)(MyComponent);
    

    The hook should then call the bound action creator in the effect, which will dispatch the action accordingly.

    Also, note that your current hook will re-run the effect every time the component is re-rendered, rather than just the first time. You'd need to modify the hook like this:

    const useFetching = someFetchActionCreator => {
      useEffect( () => {
        someFetchActionCreator();
      }, [])
    }