Search code examples
reactjsreduxreact-reduxjwtdjango-rest-framework-simplejwt

React-Redux-SimpleJWT - TypeError: logout is not a function


Running Django Rest with React-Redux and Simple JWT. Just getting to the end of authentication being done. Everything for my auth is working great except for logging out. When I click logout, it tells me the action is not a function.

Error:

 TypeError: logout is not a function
    logout_user
    src/containers/Home.js:13
      10 | const [redirect, setRedirect] = useState(false);
      11 | 
      12 | const logout_user = () => {
    > 13 |     logout();
   ^  14 |     setRedirect(true);
      15 | };
      16 | 

Actions/Auth.js:

export const logout = () => dispatch => {
dispatch({
    type: LOGOUT
});

Reducers/Auth.js:

case LOGOUT:
        localStorage.removeItem('access');
        localStorage.removeItem('refresh');
        return {
            ...state,
            access: null,
            refresh: null,
            isAuthenticated: false,
            user: null
        }

Containers/Home.js:

import React, { Fragment, useState } from 'react';
import { Link, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import logo from '../assets/logo.png'
import { logout } from '../actions/auth';



const Home = ( logout, isAuthenticated) => {
    const [redirect, setRedirect] = useState(false);

    const logout_user = () => {
        logout();
        setRedirect(true);
    };

    const guestLink = () => (
        <Fragment>
            <li className='login-link'>
                <Link to='/login'>Login</Link>
            </li>
        </Fragment>
    );

    const authLinks = () => (
        <li className='login-link'>
            <a  onClick={logout_user}>Logout</a>
        </li>
    );

...

const mapStateToProps = state => ({
    isAuthenticated: state.auth.isAuthenticated
});

export default connect(mapStateToProps, { logout })(Home);

Not sure what I'm missing here. Went through each file and tried to rework each but nada.


Solution

  • I think it's better to use the useDispatch hook to dispatch an action in redux, and your actions must be plain objects, but actually, the scenario of dispatch should be moved to your component, and the main problem is in Containers/Home.js, you forgot to destructure your props. here is the sample code that works carefully:

    Actions/Auth.js:

    const logout = () => ({
        type: "LOGOUT",
    });
    

    Containers/Home.js:

    const Home = ({ logout, isAuthenticated }) => {
        const [redirect, setRedirect] = useState(false);
        const dispatch = useDispatch();
    
        const logout_user = () => {
            dispatch(logout());
            setRedirect(true);
        };
    
        const guestLink = () => (
            <Fragment>
                <li className="login-link">
                    <Link to="/login">Login</a>
                </li>
            </Fragment>
        );
    
        const authLinks = () => (
            <li className="login-link">
                <a onClick={logout_user}>Logout</a>
            </li>
        );
    };
    
    const mapStateToProps = state => ({
        isAuthenticated: state.auth.isAuthenticated
    });
    
    export default connect(mapStateToProps, { logout })(Home);