0
votes

I'm learning Redux and have come across an issue when trying to use redux-thunk. I'm using Redux for a Chrome extension i'm building using this . Here is the setup I have at the moment:

Index.js:

import {applyMiddleware,createStore} from 'redux';
import combineReducers from './reducers/index';
import {wrapStore} from 'react-chrome-redux';
import thunk from 'redux-thunk';

const middleware = applyMiddleware(thunk);
const store = createStore(combineReducers,{}, middleware);

store.subscribe(() => {
  console.log(store.getState().lastAction);
});

wrapStore(store, {
  portName: 'example'
});

reducers/index.js:

import {combineReducers} from 'redux';
import userAuthReducer from './userAuthReducer';
import manageTeamsReducer from './manageTeamsReducer';

function lastAction(state = null, action) {
  return action;
}

export default combineReducers({
  lastAction,userAuthReducer,manageTeamsReducer
});

manageTeamsReducer:

const initialState = {
  userTeams: []
};

const manageTeamsReducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_USER_TEAMS': {
      const newState = Object.assign(state, {
        userTeams:action.teams
      });
      return newState;
    }
    default:
      return state;
  }
}

export default manageTeamsReducer;

actions.js

export const getUserTeams = () => {

// if I uncomment the below block and make it a normal action then it works as desired
/*  return {
        type: "SET_USER_TEAMS",
        teams:[{_id:"asd",name:"fwewef"}]       
    }*/

//this action below is the thunk action that currently does not work
 return dispatch => {
      dispatch({
        type: "SET_USER_TEAMS",
                teams:[{_id:"asd",name:"fwewef"}]
      });
  };
};

Component:

import React, {Component} from 'react';
import {connect} from 'react-redux';
import { bindActionCreators } from 'redux';
import * as authActions from '../../../../../../event/src/actions/userAuthActions';
import * as teamActions from '../../../../../../event/src/actions/manageTeams';

var cookies = require('browser-cookies');

class Login extends Component {

login(event) {
  this.props.actions.authActions.setUserLoggedInState(true)
  this.props.actions.teamActions.getUserTeams()     
}

  render() {
    return (
      <div className="login-par">
                <div onClick={this.login.bind(this)}></div>             
      </div>
    );
  }
}

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

const mapDispatchToProps = (dispatch) => {
  return {
        actions:{
            authActions: bindActionCreators(authActions,dispatch),
            teamActions: bindActionCreators(teamActions,dispatch)
    }}
};

export default connect(mapStateToProps,mapDispatchToProps)(Login);

What should happen is when this.login function is triggered on click in the component it should fire off the two actions. The first action: this.props.actions.authActions.setUserLoggedInState(true) fires off no problem and does exactly what it should. This is because it's a regular Redux action that simply returns an object with a type and payload.

The second action however needs to be a Thunk and no matter how I re-arrange my code with examples I find online I can't seem to get it to work. If I uncomment the first return statement in actions.js and comment out the second return statement hence making it a regular action then it works fine but I need to be able to use Thunk.

Not sure if anyone can spot if i've maybe setup Redux-Thunk wrong or anything else?

Note: there's a chance it there could be a different way to implement it due to the react-chrome-redux package i'm using but I have seen people who use the same package like here and upon installing their package it seems they've managed to make it work fine - I can't however see why mine won't work.

EDIT

I have implemented the aliases as per Sidney's recommendation as follows:

Index.js:

import {applyMiddleware,createStore} from 'redux';
import combineReducers from './reducers/index';
import {wrapStore,alias} from 'react-chrome-redux';
import thunk from 'redux-thunk';
import aliases from './aliases/aliases';

const middlewares = applyMiddleware([alias(aliases), thunk]);
const store = createStore(combineReducers,{}, middlewares);

store.subscribe(() => {
  console.log(store.getState().lastAction);
});

wrapStore(store, {
  portName: 'example'
});

Aliases.js

const getUserTeams = (orginalAction) => {
  return (dispatch, getState) => {
      dispatch({
        type: "SET_USER_TEAMS_RESOLVED",
                teams:[{_id:"asd",name:"it worked!"}]   
      });
  };
};

export default {
  'SET_USER_TEAMS': getUserTeams // the action to proxy and the new action to call
};

actions.js

export const getUserTeams = () => {
    return {
        type: "SET_USER_TEAMS",
        teams:[]        
    }
};

reducer.js

const initialState = {
  userTeams: []
};

const manageTeamsReducer = (state = initialState, action) => {
    console.log(action)
  switch (action.type) {
    case 'SET_USER_TEAMS_RESOLVED': {
      const newState = Object.assign(state, {
        userTeams:action.teams
      });
      return newState;
    }
    default:
      return state;
  }
}

export default manageTeamsReducer;

Component

There is nothing changed in the component as my understanding is I should still be dispatching the same action:

this.props.actions.teamActions.getUserTeams()

It's still not returning me the new object with "it worked!" as the payload in the app. I've tried to follow the example and documentation as best I can. Not sure if i've missed out anything?

1

1 Answers

1
votes

You need to use an alias, which is provided by the react-chrome-redux library.

The problem you're having right now is that the asynchronous action returns a function, which can't be sent to the background page over the messaging protocol. Instead, you'd dispatch a normal object-action, which is defined in an alias as a thunk.

The boilerplate repo that you linked has an example of how to set up and use aliases.