0

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',
  },
});
Sinan Samet
  • 6,432
  • 12
  • 50
  • 93

1 Answers1

1

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?

Community
  • 1
  • 1
Mark Williams
  • 2,268
  • 1
  • 11
  • 14
  • In my last piece of code is shown how I dispatch my actions. – Sinan Samet Nov 08 '16 at 14:08
  • You said you called it with actions.getFacebookUser(e.profile) - this just returns an action, it will only be disptched if this is hooked to dispatch using connect (agreed, this is what , bindActionCreators is meant to do). From your code I can't see where (say) a component event is being mapped to that action. – Mark Williams Nov 08 '16 at 14:16
  • That's why I suggest to get it working use a mapDispatchToProps function to link up the event to the appropriate action and dispatch it from within that function. Once that's working correctly you can refactor it to take advantage of bindActionCreators if that's appropriate. – Mark Williams Nov 08 '16 at 14:18
  • I have editted my question to contain the whole home.js instead to be sure I don't leave out anything. I have done this in a previous app I don't understand what's going wrong this time. It's exactly like I did it there. – Sinan Samet Nov 08 '16 at 14:25
  • Thank you that makes sense I will look into it – Sinan Samet Nov 08 '16 at 15:38
  • I don't think I understand it. I tried adding this to the actions in my connect `onLogin: () => dispatch(facebookActions),` But that didn't make it work. – Sinan Samet Nov 08 '16 at 16:13
  • It can be a bit tricky to get your head round. I'd suggest watching Dan's first egghead.io course; it's quite short and very informative. You see him using connect to join up a container with child components and using mapDispatchToProps. Follow that through and I think it'll get you there. I wopuldn't get too hung up on bindActionCreators until you've got it working. – Mark Williams Nov 08 '16 at 16:28
  • I tried it in a onPress in a TouchableHighlight function just to make sure since that does work in my other app so I did it the exact same way but it still gives me the same error. I watched the video and did it that way and it still doesn't work. – Sinan Samet Nov 08 '16 at 17:37
  • Sorry it's still not working; I'd follow the video with a small app of your own (to remove all the complexity in your current application) and get the concept of it working that way, hopefully you'll then be able to translate it to your app, – Mark Williams Nov 08 '16 at 18:02
  • As I said orignally, you can call dispatch with the action directly, so pass a reference to a function that does this to your child component which will invoke it on login/click/whatever. Once you've established you can dispatch the action with the required effects then you can use connect to hook up the dispatch and the child component. Baby steps - always the best way! Good luck! – Mark Williams Nov 08 '16 at 18:05
  • After adding a test function to both actions, types, and the reducer it somehow started working. I think it was a syntax error somewhere still not sure where. But besides that the code is still exactly the same – Sinan Samet Nov 08 '16 at 18:10
  • 1
    Good stuff, all the best! – Mark Williams Nov 08 '16 at 18:34