Jason
Jason

Reputation: 4130

Why Is My Redux Reducer Ignoring Await on Async Functions?

In my React-Native app, I had some database code that worked fine. However, I decided that I needed to shoehorn in redux to maintain certain state, especially app settings.

Once I got the redux concepts through my thick skull and implemented it, that same database code started returning promises instead of honoring the "await" statements that were previously in use.

Here is the relevant reducer and database code:

// relevant imports
export default function divisionReducer(state = {programId: 1}, action) {

    switch (action.type) {
        case GET_DIVISIONS_BY_PROGRAM:

            // add result to state
            return _.cloneDeep({...state, divisions: divisions });

        default:
            return state;
    }

}

getAllDivisions = async (programId) => {

        let db = await openDefault();

        const sql = "SELECT * FROM DIVISION WHERE DIVISION_PROGRAM_ID = ?";

        let sqlResult = await query(db, sql, [programId]);

        await close(db);

        // function to convert db snake case to camelcase
        result = keysToCamelCase(sqlResult.result);

        return result;

}

My question: why is this code not honoring the "await" keywords?

Edit: More Code Added by Request

Below is the divisionAction code:

import { GET_DIVISIONS_BY_PROGRAM } from "./actionTypes";

export const getAllDivisions = (programId) => {

    return {
        type: GET_DIVISIONS_BY_PROGRAM,
        payload: programId
    }
}

Below is the DivisionManagementScreen, which calls the getAllDivisions code:

port React, {Component} from "react";
import {View, FlatList, Alert} from "react-native";
import {withNavigation} from "react-navigation";
import {connect} from "react-redux";

import masterStyles, {listPage, bigButtonStyles} from "./../../styles/master";

import {getAllDivisions} from "./../../redux/actions/divisionActions";

import DivisionManagementRow from "./DivisionManagementRow";

class DivisionManagmementScreen extends Component {

    constructor(props) {
        super(props);

    }

    async componentDidMount() {

        this.props.getAllDivisions(this.props.programId);
        console.log("Props after getAllDivisions: " + JSON.stringify(this.props));
    }

    async componentWillUnmount() {

        console.log("Entered componentWillUnount()");

    }

    _renderItem = ({item}) => (
        <DivisionManagementRow divisionId={item.DIVISION_ID} divisionName={item.DIVISION_NAME}
            onAddTeam={() => {this._addTeam(item.DIVISION_ID)}}
            onEdit={() => {this._editDivision(item.DIVISION_ID)}}
            onDelete={() => {this._btnDeleteDivision(item.DIVISION_ID)}}/>        

    );


    render() {
        console.log("In render(), props: " + JSON.stringify(this.props));
        return (
            <View style={masterStyles.component}>
                <View style={listPage.listArea}>
                    <FlatList 
                        data={this.props.divisions}
                        renderItem={this._renderItem}
                        keyExtractor={(item) => item.DIVISION_ID.toString() } />
                </View>        
                <View style={listPage.bottomButtonArea}>
                    <PortableButton defaultLabel="Add Division"
                        disabled={false}
                        onPress={() => {this._addDivision()}}
                        onLongPress={() => {}}
                        style={bigButtonStyles} />
                </View>
            </View>
        );
    }
}

function mapStateToProps(state) {
    return {
        programId: state.divisionReducer.programId,
        divisions: state.divisionReducer.divisions
    };
}

export default withNavigation(connect(mapStateToProps, {getAllDivisions})(DivisionManagmementScreen));

Is this enough code to diagnose?

Upvotes: 0

Views: 584

Answers (2)

Jason
Jason

Reputation: 4130

So, instead of writing my database-enabled action creator correctly (starting with " return (dispatch) => { /* blah blah blah */ } ), I was still having it return an object, and having the reducer call the method with the database code.

I finally got the concepts through my thick skull, and got the code working over a weekend.

Upvotes: 0

Jed Richards
Jed Richards

Reputation: 12437

I can't see where you're actually calling your getAllDivisions async function. I can only see you trying to call the getAllDivisions action creator - action creators just emit actions syncronously, by default they can't call functions with side effects.

If you want to trigger side effects, like your DB async function you need to look into a library like redux-thunk. Or more advanced would be redux-saga. If you're new to this stuff, I advise starting with redux-thunk.

Also I think the way you're using the connect() function is wrong. The second argument mapDispatchToProps needs to actually dispatch your actions to the store. So it should look like this:

function mapStateToProps(state) {
    return {
        programId: state.divisionReducer.programId,
        divisions: state.divisionReducer.divisions
    };
}

function mapDispatchToProps(dispatch) {
    return {
        getAllDivisions () {
          dispatch(getAllDivisions())
        }
    };
}

export default withNavigation(
  connect(
    mapStateToProps, mapDispatchToProps
  )(DivisionManagmementScreen)
)

Upvotes: 1

Related Questions