Aleistor Crawford
Aleistor Crawford

Reputation: 35

React Native Redux - Why can't I access data in my redux store and display it?

I completed the React Native course on Coursera and have a working app using redux and json-server to show data. I am now making my own app and I'm having a lot of trouble with redux not showing my data when I try to access it.

After trying to figure out the problem myself I eventually just copied all the redux files from my previous project and configured that to work. After editing them all to display my current data I started having issues again, I accidentally deleted my git commit of the working code and have reverted back to the state of just after copying all the files. I can no longer have my flatlist in homecomponent show any data.

I have condensed the code into its simplest form hoping to get some assistance.

I'm basically just trying to use a FlatList to show data from my redux store using MapStateToProps. In its current state the list is not shown at all, which to me means it has no data to show. It has definitely worked in a different iteration and showed the data from my db.json file. I'm not sure why it isn't working now.

HomeComponent.js

import React, { Component } from 'react';
import { View, Image, FlatList} from 'react-native';
import { ListItem } from 'react-native-elements';
import { connect } from 'react-redux';
import { baseUrl } from '../shared/baseUrl';

const mapStateToProps = state => {
    return{
        dishes: state.dishes
    }
}

class HomeScreen extends Component {
    render() {

        const renderCategory = ({item, index}) => {
            return (
                <ListItem
                    key={index}
                    title={item.name}
                    subtitle={item.description}
                    hideChevron={true}
                    leftAvatar={{ source: { uri: baseUrl}}}
                    />
            );
        }
        return (
            <View>
                <Image
                    source = {{ uri: baseUrl + 'images/ezywhip.png'}}
                    style={{width:200, height: 200}}
                />
                <FlatList 
                    data={this.props.dishes.dishes}
                    renderItem={renderCategory}
                    keyExtractor={item => item.id.toString()}
                />
            </View>

        );
    }
}

export default connect(mapStateToProps)(HomeScreen);

ActionCreator.js

import * as ActionTypes from './ActionTypes';
import { baseUrl } from '../shared/baseUrl';


export const fetchDishes = () => (dispatch) => {
    
    dispatch(dishesLoading());

    return fetch(baseUrl + 'dishes')
    .then(response => {
        if (response.ok) {
            return response;
        } else {
            var error = new Error('Error ' + response.status + ': ' + response.statusText);
            error.response = response; 
            throw error;
        }
    },
    error => {
        var errmess = new Error(error.message);
        throw errmess;
    })
    .then(response => response.json())
    .then(dishes => dispatch(addDishes(dishes)))
    .catch(error => dispatch(dishesFailed(error.message)));
};

export const dishesLoading = () => ({
    type: ActionTypes.DISHES_LOADING
});

export const dishesFailed = (errmess) => ({
    type: ActionTypes.DISHES_FAILED,
    payload: errmess
});

export const addDishes = (dishes) => ({
    type: ActionTypes.ADD_DISHES,
    payload: dishes
});

ActionTypes.js

export const DISHES_LOADING = 'DISHES_LOADING';
export const ADD_DISHES = 'ADD_DISHES';
export const DISHES_FAILED = 'DISHES_FAILED';

ConfigureStore.js

import { createStore, applyMiddleware, combineReducers } from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';
import { dishes } from './dishes';

export const ConfigureStore = () => {
    const store = createStore(dishes,
        applyMiddleware(thunk, logger)
    );

    return store;
}

dishes.js

import * as ActionTypes from './ActionTypes';

export const dishes = (
    state = {
        isLoading: true,
        errMess: null,
        dishes: []
    },
    action) => {
        switch(action.type) {
            case ActionTypes.ADD_DISHES:
                return{...state, isLoading: false, errMess: null, dishes: action.payload};

            case ActionTypes.DISHES_LOADING:
                return{...state, isLoading: true, errMess: null, dishes: []};

            case ActionTypes.DISHES_FAILED:
                return{...state, isLoading: false, errMess: action.payload};

            default:
                return state;
        }
    }

MainComponent.js

import React, { Component } from 'react';
import { StyleSheet } from 'react-native';
import AccountScreen from './AccountComponent';
import CartScreen from './CartComponent';
import DetailScreen from './DetailsComponent';
import HomeScreen from './HomeComponent';
import MenuScreen from './MenuComponent';
import OrderScreen from './OrderComponent';
import SearchScreen from './SearchComponent';

import { createStackNavigator } from '@react-navigation/stack';
import { NavigationContainer, StackActions } from '@react-navigation/native';
import { createMaterialBottomTabNavigator } from '@react-navigation/material-bottom-tabs';

import { connect } from 'react-redux';
import { fetchDishes } from '../redux/ActionCreators';

const mapStateToProps = state => {
    return {
        dishes: state.dishes
    }
}

const mapDispatchToProps = dispatch => ({
    fetchDishes: () => dispatch(fetchDishes())
})

const Stack = createStackNavigator();
const TabStack = createMaterialBottomTabNavigator();

class Main extends Component {
    componentDidMount() {
        this.props.fetchDishes();
    }

    homeStack = () =>
        <Stack.Navigator>
            <Stack.Screen
                name="Home"
                component={HomeScreen}
                options={{
                    headerShown: false,
                }}
            />
            <Stack.Screen
                name="Menu"
                component={MenuScreen}
            />
            <Stack.Screen
                name="Details"
                component={DetailScreen}
            />
        </Stack.Navigator>
    
    homeTabStack = () =>    
        <TabStack.Navigator
            activeColor="#f0edf6"
            inactiveColor="#3e2465"
            barStyle={{ backgroundColor: '#ff69b4' }}>
            <TabStack.Screen
                name="Home"
                component={this.homeStack}
            />
            <TabStack.Screen
                name="Search"
                component={SearchScreen}
            />
            <TabStack.Screen
                name="Cart"
                component={CartScreen}
            />
            <TabStack.Screen
                name="Order"
                component={OrderScreen}
            />
            <TabStack.Screen
                name="Account"
                component={AccountScreen}
            />
        </TabStack.Navigator>
    

    render() {
        return (
            <NavigationContainer>
                <Stack.Navigator 
                    initialRouteName="Home"y >
                    <Stack.Screen 
                    name="Home" 
                    component={this.homeTabStack}
                    options={{
                        headerShown: true,
                        headerTitleAlign: 'center'
                    }}
                    />
                </Stack.Navigator>
            </NavigationContainer>
        )
    }
}

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

db.json

{
    "dishes": [{
            "id": 0,
            "name": "Dish 1",
            "category": "Products",
            "label": "",
            "featured": true,
            "description": "Dish 1"
        },
        {
            "id": 1,
            "name": "Dish 2",
            "category": "Products",
            "label": "",
            "featured": false,
            "description": "Dish 2"
        },
        {
            "id": 2,
            "name": "Dish 3",
            "category": "Products",
            "label": "",
            "featured": false,
            "description": "Dish 3"
        }
    ]
}

Upvotes: 1

Views: 1103

Answers (1)

Drew Reese
Drew Reese

Reputation: 202872

I think since dishes is your "root" reducer that state is the dishes reducer state object. In other words, when you connect HomeScreen to your store, state.dishes is all you need to access the array, state.dishes.dishes is undefined.

class HomeScreen extends Component {
  render() {
    const renderCategory = ({ item, index }) => {
      return (
        <ListItem
          key={index}
          title={item.name}
          subtitle={item.description}
          hideChevron={true}
          leftAvatar={{ source: { uri: baseUrl }}}
        />
      );
    }
    return (
      <View>
        <Image
          source={{ uri: baseUrl + 'images/ezywhip.png' }}
          style={{ width: 200, height: 200 }}
        />
        <FlatList 
          data={this.props.dishes} // <-- props.dishes is the dishes state
          renderItem={renderCategory}
          keyExtractor={item => item.id.toString()}
        />
      </View>
    );
  }
}

const mapStateToProps = state => ({
  dishes: state.dishes, // <-- the dishes array from the reducer
});

export default connect(mapStateToProps)(HomeScreen);

Upvotes: 1

Related Questions