Sinan Samet
Sinan Samet

Reputation: 6742

Getting "Actions may not have an undefined "type""

I'm getting the error:

Actions may not have an undefined "type" property.

But I'm sure I defined it and spelled it right.

App:

import React, {Component} from 'react';
import { createStore, applyMiddleware, combineReducers } from 'redux';
import { Provider } from 'react-redux';
import { AsyncStorage } from 'react-native';
import thunk from 'redux-thunk';
import {persistStore, autoRehydrate} from 'redux-persist';
import FBLoginView from '../components/FBLoginView'

import * as reducers from '../reducers';
import Routing from './Routing';

const createStoreWithMiddleware = applyMiddleware(thunk)(createStore);
const reducer = combineReducers(reducers);
const store = createStoreWithMiddleware(reducer, undefined, autoRehydrate());

persistStore(store, {
    storage: AsyncStorage,
    }, () => {
})

export default class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <Routing />
      </Provider>
    );
  }
}

Actions:

import * as types from './actionTypes';

export function getFacebookUser(user) {
  return {
    type: types.GET_FACEBOOK_USER,
    user: user,
  };
}

Types:

export const GET_FACEBOOK_USER = 'GET_FACEBOOK_USER';

Reducer:

import * as types from '../actions/actionTypes';

const initialState = {
  user: {},
};

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {
    case types.GET_FACEBOOK_USER:
      return {
        ...state,
        user: action.user
      };
    default:
      return state;
  }
}

Edit (My home.js page)

import React, { Component } from 'react'
import { View, Text, StyleSheet, Image, TouchableHighlight } from 'react-native'
import { Actions } from 'react-native-router-flux'
import {FBLogin, FBLoginManager} from 'react-native-facebook-login'
import FBLoginView from '../components/FBLoginView'
import * as facebookActions from '../actions/facebookActions';
import { connect } from 'react-redux'
import {bindActionCreators} from 'redux'

class Home extends Component {
    constructor(props) {
      super(props);

      this.state = {
        login: false
      };

      console.log(this.props)
    }

  render() {
    let { facebook, actions } = this.props
    _onLogin = (e) => {
        actions.getFacebookUser(e.profile)
        console.log(facebook)
    }

    _onLogout = (e) => {
        console.log(e)
    }

    return (
      <View style={styles.background}>
            <Text>{this.state.login ? "Logged in" : "Logged out"}</Text>
            <FBLogin
                buttonView={<FBLoginView />}
                ref={(fbLogin) => { this.fbLogin = fbLogin }}
                loginBehavior={FBLoginManager.LoginBehaviors.Native}
                permissions={["email","user_friends"]}
                onLogin={function(e){_onLogin(e)}}
                onLoginFound={function (e){console.log(e)}}
                onLoginNotFound={function(e){console.log(e)}}
                onLogout={function(e){_onLogin(e)}}
                onCancel={function(e){console.log(e)}}
                onError={function(e){console.log(e)}}
                onPermissionsMissing={function(e){console.log(e)}}
                style={styles.fbButton}
                passProps={true}
              />
      </View>
    )
  }
}

export default connect(store => ({
    facebook: store.facebook.user,
  }),
  (dispatch) => ({
    actions: bindActionCreators(facebookActions, dispatch)
  })
)(Home);

const styles = StyleSheet.create({
  background: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#00796B',
  },
});

Upvotes: 0

Views: 947

Answers (1)

Mark Williams
Mark Williams

Reputation: 2308

I don't think that you're dispatching the action correctly:

actions.getFacebookUser(e.profile)

is an action creator and will just return the action, not dispatch it.

I can't see your Home component that you're hooking up with Connect but I'd guess this is the source of events that you will want to dispatch as actions. Why not try dispatching directly against the store, and then move to use connect to hook up with mapDispatchToProps? Finally you can use bindActionCreators if this is necessary.

There are two very good (free) egghead.io courses that will help here, both by Dan Abramov:

https://egghead.io/courses/getting-started-with-redux

https://egghead.io/courses/building-react-applications-with-idiomatic-redux

and the docs are also very good, but I guess you've seen them.

After seeing more of the code, I can't see how the component you're connecting (Home) is linking its events (for example onLogin) to a dispatch property. I can see it caling its own internal function called _onLogin, but this just in turn call the action creator, it won't dispatch.

The connect function allows you connect properties on a component (here, Home) with the redux store; it effectively links, in your example, the 'onLogin' property of your Home component with a particular action and can then dispatch that action to the store.

So,your Home component needs to accept a property like 'onLogin' that it can then call; mapDispatchToProps is a function you write to marry up your child component's properties to dispatch actions. bindActionCreators is just a further helper to bind to action creators; it may be overkill in your current use case.

Dan Abramov explains this so much better than I can, so see the docs, but also see his answer here:

How to get simple dispatch from this.props using connect w/ Redux?

Upvotes: 1

Related Questions