0
votes

I am new to redux and I'm having trouble with setting it up.

I am trying to dispatch an action whenever I click the login button. but the reducer does not get called. Using Thunk, I can see that my action DOES get dispatched. My terminal prints previous state, current action, and next state whenever I click the login button and I've successfully used console.log in LoginAction.js.

That said, the emitted action does not seem to call my reducer to act. I tried console.log in my reducer, and it doesn't print anything. The current action displayed by Thunk is also displayed as empty and my initialState does not change

Login.js

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { login } from './LoginAction';

const mapDispatchToProps = (dispatch) => {
    return{
        login: () => {dispatch(login())},
    }
};

const mapStateToProps = (state) => {
    return{
        userInfo: state.userInfo
    }
};

const Login = connect(mapStateToProps, mapDispatchToProps)(
    class Login extends Component {
        onLogin() {
            this.props.login();
        }

        render() {
            return (
                <View>
                    <TouchableHighlight 
                        onPress={() => this.onLogin()}>
                    </TouchableHighlight>
                </View>
            );
        }
    }
)

LoginAction.js

import { URL } from '../../core/api';
import { fetchPost } from '../../core/util';

export const LOGIN_REQUESTED = "LOGIN_REQUESTED";
loginRequested = () => {
    console.log("in request");
    return {
        type: LOGIN_REQUESTED,
    };
}


export const LOGIN_RECEIVED = "LOGIN_RECEIVED";
loginReceived = (loginAttemptResult) => {
    console.log("in receive");
    console.log(JSON.stringify(loginAttemptResult));
    return {
        type: LOGIN_RECEIVED,
        loginAttemptResult
    };
}

export function login() {
    let loginApi = URL + "/login";
    console.warn(loginApi)

    return (dispatch) => {
        dispatch(loginRequested());
        const formData = {
            email: '[email protected]',
            id: '000000000000'
        }
        fetchPost(loginApi, formData)
            .then(loginAttemptResult => {
                console.log(loginAttemptResult);
                dispatch(loginReceived(loginAttemptResult));
            })
            .catch(console.log("fail :("));
    };
}

In LoginAction.js, my console.log prints "in request", "in receive", and "fail :(". However, I've made sure that the HttpRequest/Fetch is successful by printing the content of the payload

LoginReducer.js

import {LOGIN_REQUESTED, LOGIN_RECEIVED} from "./LoginAction";
import {RESPONSE_STATUS} from "../../constants";
import {userInfoState} from "../../core/initialState";

export default function loginReducer(state = userInfoState, action) {
    switch (action.type) {
        case LOGIN_REQUESTED:{
            console.log("reducer 1");
            return Object.assign({}, state, {
                isLoggingIn: true
            });
        }
        case LOGIN_RECEIVED: {
            console.log("reducer 2");
            const {status, message} = action.loginAttemptResult;
            const errorMsg = (status === RESPONSE_STATUS.ERROR) && message;
            return Object.assign({}, state, {
                isLoggingIn: false, errorMsg,
            });
        }
        default:
             console.log("default reducer");
             return state;
    }
}

Nothing in LoginReducer.js got printed in my console

store.js

import { AsyncStorage } from 'react-native';
import { createStore, applyMiddleware, compose } from 'redux';
import { persistStore, autoRehydrate } from 'redux-persist';
import { REHYDRATE, persistCombineReducers } from 'redux-persist';
import createActionBuffer from 'redux-action-buffer';
import thunk from 'redux-thunk';
import { createLogger } from 'redux-logger';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'

import loginReducer from '../screens/Login/LoginReducer';

let storage = AsyncStorage;

const config = {
    key: 'root',
    storage,
    stateReconciler: autoMergeLevel2
}

export default function configureStore() {

    let reducer = persistCombineReducers(config, {
        userInfo: loginReducer,
    });

    const middleware = [thunk];
    middleware.push(createLogger());

    middleware.push(createActionBuffer(REHYDRATE));
    const store = createStore(
        reducer,
        undefined,
        compose(applyMiddleware(...middleware)),
    );

    persistStore(
        store,
        null,
    );
    return store;
}

My suspicion is that I've got something wrong in my store.js, but I can't figure it out.

This is my first question on the site and English is not my native language. If something is unclear and needed clarification, please ask

Edit: This is the log from thunk

Login button clicked
in request
action LOGIN_REQUESTED 
prev state Object {
    "userInfo": Object {...},
}
action Object {
    "type": "LOGIN_REQUESTED",
}
next state Object {
    "userInfo": Object {...},
}
fail :(
Object {
    "data": Array [
            Object {
                ...
            },
        ],
    "message": "success",
    "status": 1,
}
in receive
action Object {
    "loginAttemptResult": Object {
        "data": Array [
            Object {...},
        ],
        "message": "success",
        "status": 1,
    },
    "type": "LOGIN_RECEIVED",
}
next state Object {
    "userInfo": Object {
    ...
    },
}
1
Just a guess, but in your reducer switch your types are written as variables, not strings. The reducer is listening for an action with type 'LOGIN_REQUESTED' but instead you're passing it the action directly. Reducers listen for dispatched actions. There's no need to import the action in the reducer. - FranCarstens
It was the formatting of my previous company. I tried changing the variables to strings as you suggested, but it doesn't change anything - sagungrp
In your store your createStore function adds preloaded state as undefined. I'm not sure if this would break anything, but the docs require "must be a plain object with the same shape as the keys passed to it. Otherwise, you are free to pass anything that your reducer can understand." If you don't have a preloaded state it should be safe to leave it out. - FranCarstens
You should go step by step. After properly defining your functions, be sure to see loginAttemptResult. After this put a console.log in your reducer as @FranCarstens. But I prefer the top line, not a particular case. - devserkan
Are you 100 that your actions are being dispatched? What does your action log look like in console? - FranCarstens

1 Answers

0
votes

I can't examine all the codes (such as a complex store for me) but the only mistake I can see here is you are not properly defining loginRequested and loginReceived functions in your action creators file.

const loginRequested ...
const loginReceived ...

So, maybe they are not triggered at all and your action does not hit the reducers.