useDispatch using lower version of react-redux

Viewed 1923

I am encountering a function not found using useDispatch. Supposedly, I should be using react-redux, unfortunately, my version is 6.0.0 and what's needed is 7.0.0 and above. I'd like to explore useDispatch or related hook to dispatch an action function inside a function component. How do I do this given that I cannot upgrade my react-redux & still use function component?

My alternative is to use class component, but again, I'd like to see this work in function component. Let me know what other details needed.

Here's my code.

import React, { useDispatch } from 'react';
import {
    Tooltip,
    IconButton,
    Icon,
} from '@material-ui/core';
import { logout } from './auth/store/actions';

const QuickLogout = () => {
  const dispatch = useDispatch();

  const handleClick = () => {
    dispatch(logout());
  };

  return (
    <Tooltip title="Logout" placement="bottom">
        <IconButton className="w-64 h-64" onClick={handleClick}>
            <Icon>exit_to_app</Icon>
        </IconButton>
    </Tooltip>
  );
};

export default QuickLogout;

And here's the error when compiling.

TypeError: Object(...) is not a function
QuickLogout
webpack-internal:///.....onents/QuickLogout.js:18:75

enter image description here

Edit: I mentioned exploring useDispatch or related hooks given that I cannot upgrade. I felt that this is a gray statement as I really just wanted my code to work. That means, solution is not limited to useDispatch or other hooks. Hence, I chose the answer that did not use useDispatch or hooks because it was plain simple. Apologies for the vague statement. I'll take note on improving my writing skills.

2 Answers

React itself doesn't have useDispatch in it Hooks API, but it has useReducer to eliminate redux for a small project that redux is an overengineering process for them.

On the other hand, new versions of react-redux provide new handy hooks which you can make a similar version of those by yourself.

Here is a Tip

Hooks (React hooks) can only be used in functional component
HOC (Higher-order component) can be used anywhere

The connect function which react-redux provides is HOC so it can also be used with both class-base and functional components. It is also a good practice to separate your presentation UI and logic into representationals and containers, hence there will be no problem for your component to be functional and use all fancy things that could be used in traditional class-component and connect by react-redux.

you can also make your custom hook for handling such things in a re-usable manner with less code.

// setup.js
const store = createStore(/* put your reducer and enhancers here */)
export const { dispatch, getState } = store

// hooks.js
import { dispatch, getState } from '~setup.js'

export const useDispatch = () => dispatch
export const useSelector = selector => selector(getState())
// The above useSelector wont cause your component to re-render on data change 

Then in your component

import { useDispatch } from '~hooks.js'
import { logout } from './auth/store/actions'

export default function QuickLogout() {
  const dispatch = useDispatch()
  
   const handleClick = () => {
    dispatch(logout())
  }

  return (
    <Tooltip>
        <IconButton onClick={handleClick}>
            <Icon>exit_to_app</Icon>
        </IconButton>
    </Tooltip>
  )
}

If you want to know more about custom hooks see making my own hook.

If you can't upgrade your react-redux version to one with the useDispatch and useSelector React hooks you can still use the connect Higher Order Component to inject dispatch, or to even more simply wrap your action creators with a call to dispatch.

import { connect } from 'react-redux';

const QuickLogout = ({ logout }) => { // <-- destructure logout prop
  return (
    <Tooltip title="Logout" placement="bottom">
      <IconButton
        className="w-64 h-64"
        onClick={logout} // <-- assign to click handler
      >
        <Icon>exit_to_app</Icon>
      </IconButton>
    </Tooltip>
  );
};

const mapDispatchToProps = {
  logout, // <-- inject logout action as prop already wrapped by dispatch!
};

const ConnectedQuickLogout = connect(
  null, // <-- this is typically mapStateToProps, but we don't need it
  mapDispatchToProps,
)(QuickLogout);

export default ConnectedQuickLogout;

If you prefer to keep the code closer to as-is then you can simply connect it to the redux store and a dispatch prop is still injected.

import { connect } from 'react-redux';

const QuickLogout = ({ dispatch }) => {
  const handleClick = () => {
    dispatch(logout());
  };

  return (
    <Tooltip title="Logout" placement="bottom">
        <IconButton className="w-64 h-64" onClick={handleClick}>
            <Icon>exit_to_app</Icon>
        </IconButton>
    </Tooltip>
  );
};

export default connect()(QuickLogout);
Related