Skip to content
Advertisement

Undefined is not a function (near ‘… map …’)

When I tap in the Pressable element in the JSX I get the error : Undefined is not a function (near ‘… wines.map …’). The log says it’s coming from the wines.map loop in the JSX. I’m unsure on what could be wrong with how I’m trying to change the data in the toggle function or how I set the default useState array object. The code is supposed to toggle between two different kind of images for each button independently.

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */
import 'react-native-gesture-handler';
import React, {useState} from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import {
  SafeAreaView,
  StyleSheet,
  ScrollView,
  View,
  Text,
  StatusBar,
  ImageBackground,
  Image,
  TextInput,
  Button,
  TouchableNativeFeedback,
  TouchableWithoutFeedback,
  TouchableOpacity,
  TouchableHighlight,
  FlatList,
  Pressable,
  RecyclerViewBackedScrollViewComponent
} from 'react-native';

import { Immersive } from 'react-native-immersive';


const fullWine = require('../images/selected-wine.png');
const emptyWine = require('../images/empty-wine-icon.png');



const WineList = () => {


    Immersive.on()
    Immersive.setImmersive(true)



    const [wines, setWines] = useState([
 
        {
            name: "2018 Prezzo",
            info: "What dsbetter way to spend a lazy afternoon than sipping away on this wine.",
            imageUrl: emptyWine

        },
        {
            name: "2018 Coqueta",
            info: "A litstle flirty wine.",
            imageUrl: emptyWine
        }
       
    ])
  
    function toggle(pressedWine){

        let oldWines = [...wines]

        
        let newWines = oldWines.map((wine) => {
            
            if(wine === pressedWine){
                if(wine.imageUrl == emptyWine){
                    wine.imageUrl = fullWine;
                } else {
                    wine.imageUrl = emptyWine;
                }
            }
            return wine;
        });
       
        setWines({newWines});

        // setWines({newWines});
    }
   

    return (
    <View style={{flex:1}}>  
        <ScrollView style={styles.scrollView}>
            <View style={styles.headerMessage}>
                <Text style={styles.headerMessageText}>Select your wines for tasting</Text>
            </View>

            <View style={[styles.wineListWrapper]}>

                { wines.map((wine, index) => {
                    return(
                    <View key={index} style={[styles.item]}>
                        <Image source={require('../images/Peresozo2018.png')} style={[styles.bottle]} />

                        <View style={[styles.infoWrapper]}>
                        
                    
                            <Text style={[styles.itemTitle]}>{wine.name}</Text>
                            <Text style={[styles.itemInfo]}> 
                            
                                {wine.info}
                            
                            </Text>
                        </View>

                        <Pressable onPress={ (wine) => toggle(wine) }  style={[styles.wineIcon]}>
                            <Image source={wine.imageUrl}  />
                        </Pressable>


                    </View>
                    )
                
                })}

                 
            </View>
        </ScrollView>
        
        <TouchableOpacity  onPress={() => alert('yo') }  style={[styles.footerButton]}>
            <Text style={[styles.footerText]}>Start Tasting</Text>
        </TouchableOpacity>
    </View>    
        
    )
}

const styles = StyleSheet.create({
    footerButton:{
        flex:1,
        justifyContent: 'flex-end',
        alignContent:'center',
        alignItems:'center',
        backgroundColor:'white',
        paddingTop:90
    
    },
    footerText:{
        fontFamily: 'Charm-Regular',
        fontSize:40,
        color:'#624124'
        
        
    },
    item:{
        flex:1,
        flexDirection: 'row',
        justifyContent: 'space-between',
        padding: 10
    },
    infoWrapper:{
        flex:0.7, 
        flexWrap: 'wrap', 
        flexDirection: 'row', 
        padding:10, 
        alignSelf:'flex-start',
        justifyContent: 'space-between',
        marginTop: -30,
        marginLeft:1
    },
    itemTitle:{
        color:'white',
        fontFamily: 'Charm-Regular',
        fontSize: 40,
        
    },
    itemInfo:{
        color:'white',
        fontSize: 20,
        
    },
    wineIcon:{
        padding:5,
        flex:0.15
    },
    wineListWrapper:{
        marginLeft: 10,
        marginTop: 40
    },
    bottle:{
        marginLeft: 2,
        width: 80,
        height: 250,
        resizeMode: 'contain',
       
        
    },
    scrollView:{
        backgroundColor: '#4B4239',
    },
    headerMessage:{
        backgroundColor: 'white',
        flex: 1,
        alignItems: 'center',
        alignContent: 'center',
        justifyContent: 'center',
        flexDirection: 'column',
        alignSelf: 'center',
        width:400,
        borderRadius: 4,
        padding: 0,
        marginTop: 10


    },
    headerMessageText:{
        color: '#4B4239',
        textAlign: 'center',
        fontSize: 30,
        fontFamily: 'Charm-Regular',
        lineHeight: 50
    }

})

export default WineList

Advertisement

Answer

The issue is that you’re setting an object into the wines state when updating it:

setWines({ newWines });

Since the value of the state is an array, you probably meant:

setWines(newWines);

Additionally, the parameter passed to the onPress callback is not the wine object, but a PressEvent. As a result, you’re shadowing the wine variable from the .map() with the event object from the callback’s parameter.

You probably meant to pass the wine from the loop to toggle instead, so just remove the (wine) => parameter.

<Pressable onPress={() => toggle(wine)} style={[styles.wineIcon]}>
  <Image source={wine.imageUrl} />
</Pressable>
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement