0

I am trying to display a list of buttons in a custom drawer component in React Native. The buttons successfully load and render, but immediately become "undefined" and are thus un-clickable. The specific error I am getting is " undefined is not an object (evaluating 'props.screenProps.data.menu.items') " when I click on the buttons. The app works fine before clicking on the buttons, and they are viewable.

I tried using some JS to only display the buttons if they are not undefined, but then the buttons just don't show up because they are undefined. My data is stored in redux.

My custom drawer:

const CustomDrawerComponent = (props) => (
    <Provider store={store}>
        <SafeAreaView style={{ flex: 1 }}>
        <View style={{height: 150, backgroundColor: 'white', alignItems: 'center', justifyContent: 'center'}}>
            <Text style={{marginTop: 50}}> Header Image / Logo</Text>
        </View>    
            <ScrollView>
            { //props.screenProps shows my list of buttons correctly, but clicking on them gives
            //the error of "undefined is not an object"
            //after initially rendering, they switch immediately to undefined
            //as proved by:  '''(props.screenProps.data.menu.items == undefined) &&''' 
            //doesn't show any buttons in the drawer
                props.screenProps.data.menu.items.map((_data) => { return( SideButtonClick(_data) ) })  
                }
            </ScrollView>
        </SafeAreaView>
    </Provider>
)
const SideButtonClick = (data) => {
    return(
        <Button title={data.title} key={data.title} 
            onPress = {() => store.dispatch({
            type: "CHANGE_CURRENT_DATA",
            payload: data }) } 
          />
    );
}

edit: my reducers

export const reducer = (state = initialState, action) => {
    switch (action.type) {
        case "CHANGE_CURRENT_DATA": {
            state = {
                ...state,
                title: action.payload.title,
                link: action.payload.link,
                icon: action.payload.icon
            };
                console.log(action.payload);
                }
        case "CHANGE_DATA": {
            state = {
                ...state,
                data: action.payload
            };
             //console.log(action.payload);
        }
    }
    return state;
};
Adam Wells
  • 47
  • 6
  • I'm confused, you are sending the `screenProps` to `MyApp`, but are trying to use `props.screenProps` in `CustomDrawerComponent`?? Are you missing some code here? – Praneeth Paruchuri Sep 08 '19 at 23:35
  • Also you can `connect` any component to the store and get the required stuff than sending it again as a prop to a different component. – Praneeth Paruchuri Sep 08 '19 at 23:36
  • @paruchuri-p MyApp is the CustomDrawerComponent, yes I am missing code in my examples, but that all works just fine. I tried connecting the component to the store using var customConnect = connect(mapStateToProps, mapDispatchToProps)(CustomDrawerComponent); and that worked, but I can't seem to access my store in the customdrawercomponent this way. I edited my question to show where I use MyApp – Adam Wells Sep 08 '19 at 23:49
  • Can you check if `props.screenProps.data.menu.items && props.screenProps.data.menu.items.map()` in my experience deeply nested objects won't get loaded immediately. – Claeusdev Sep 09 '19 at 00:22
  • @Claeusdev it loads and renders fine. but when I click on the button, props.screenProps.data.menu.items becomes undefined. If I use a conditional render like you mentioned, the buttons don't show up at all. So I think that the buttons render initially, and when my redux state changes elsewhere, props.screenProps.data becomes undefined somehow, which makes the buttons undefined as well – Adam Wells Sep 09 '19 at 01:18
  • Oh okay, then it means the data change happening is setting a wrong object somewhere in the process.. – Claeusdev Sep 09 '19 at 02:29
  • Can you include the reducer for `CHANGE_CURRENT_DATA`? My hunch is that `CHANGE_CURRENT_DATA` is replacing your `state.data` so that `state.data` becomes the data for only one of the menu items in which case `state.data.menu` is then undefined. – azundo Sep 09 '19 at 04:32
  • @azundo I included it in my question. I've checked the redux state after it changes, and it is working as expected – Adam Wells Sep 09 '19 at 05:04

1 Answers1

1

You are missing return calls in your code so your case statements are falling through and state.data is getting overrwitten on the CHANGE_CURRENT_DATA type. Update your reducer to return state at the end of each case:

export const reducer = (state = initialState, action) => {
    switch (action.type) {
        case "CHANGE_CURRENT_DATA": {
            state = {
                ...state,
                title: action.payload.title,
                link: action.payload.link,
                icon: action.payload.icon
            };
                console.log(action.payload);
            return state;
                }
        case "CHANGE_DATA": {
            state = {
                ...state,
                data: action.payload
            };
             //console.log(action.payload);
           return state;
        }
    }
    return state;
};
azundo
  • 5,902
  • 1
  • 14
  • 21