Home > Software engineering >  React Native render error: null is not an object (evaluating origin.location)
React Native render error: null is not an object (evaluating origin.location)

Time:04-25

I'm fairly new to react-native and decided to try cloning an app, following a tutorial. I'm trying to pass data stored in redux to a map rendered on my home screen but when I run, I keep getting the following error: null is not an object (evaluating origin.location). Any suggestions, solutions and quick fixes are welcome. Thanks

Home screen codes


    import { View, TouchableOpacity, Text } from 'react-native'
    import { React } from 'react'
    import HeaderTabs from '../components/HeaderTabs'
    import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete'
    import { Ionicons } from '@expo/vector-icons'
    import { setDestination, setOrigin } from '../slices/navSlice'
    import { useDispatch } from 'react-redux'
    import { SafeAreaView } from 'react-native-safe-area-context'
    import { GOOGLE_MAPS_APIKEY } from '@env'
    import Map from './components/Map'
    
    const Home = ({navigation}) =>{
      const dispatch = useDispatch();
    
      return (
          <SafeAreaView style={{ backgroundColor:"white", 
                          flex:1,
                          padding:5, 
                          marginTop:-20
                          }}> 
                          
              <View style={{alignItems:"flex-end"}} >
                <TouchableOpacity onPress={() => {navigation.navigate("CustomerInfo")}}>
                  <Ionicons name="person-circle" size={30} color="black" />
                </TouchableOpacity>
              </View>
    
                <HeaderTabs />
    
                <View style={{marginTop:15, flexDirection:"row"}}>
                  
                  <GooglePlacesAutocomplete
                  query={{key: GOOGLE_MAPS_APIKEY}}
                  enablePoweredByContainer={false}
                  onPress={(data, details = null) => {
                    dispatch(setOrigin({
                      location: details.geometry.location,
                      description: data.description,
                    })
                    ); 
    
                    dispatch(setDestination(null));
                    }}
                  fetchDetails={true}
                  returnKeyType={"search"}
                  placeholder='Enter package pickup location' 
                  debounce={400}
                  nearbyPlacesAPI='GooglePlacesSearch'
                  styles={{
                      textInput:{
                          backgroundColor:"#eee",
                          borderRadius:15,
                          fontFamily:"Poppins_500Medium",
                          marginTop:10,
                          fontSize:18,
                      },
    
                      textInputContainer:{
                          backgroundColor:"#eee",
                          borderRadius:15,
                          flexDirection:"row",
                          alignItems:"center",
                          width:380
                      },
                  }}
    
                  renderLeftButton={() => (
                      <View style={{
                        marginLeft:10
                      }}>
                        <Ionicons name="location" size={20} color="green" />
                      </View>
                  )}
                  renderRightButton={() => (
                      <View style={{
                        flexDirection:"row",
                        marginRight:5,
                        backgroundColor:"white",
                        padding:9,
                        borderRadius:30,
                        alignItems:"center"
                      }}>
                        <Ionicons name="search" size={15} color="black" />
                      </View>
                  )}     
                  />
            </View>
            
            <Map />
    
          </SafeAreaView>      
        
      )};
    
      export default Home;

Map component codes


    import { View, Text } from 'react-native'
    import React from 'react'
    import MapView, { Marker } from 'react-native-maps'
    import { useSelector } from 'react-redux'
    import { selectOrigin } from '../slices/navSlice'
    
    const Map = () => {
        const origin = useSelector(selectOrigin);
    
      return (
        <MapView
            style={{flex:1, marginTop:10}}
            initialRegion={{
                latitude: origin.location.lat,
                longitude: origin.location.lng,
                latitudeDelta: 0.0922,
                longitudeDelta: 0.0421,
            }}
            />
      );
    };
    
    export default Map;

Where origin.location is coming from


const initialState = {
    origin: null,
    destination: null,
    travelTimeInformation: null
}

export const navSlice = createSlice({
    name: "nav",
    initialState,
    reducer: {
        setOrigin: (state, action) => {
            state.origin = action.payload; 
        },
        setDestination: (state, action) => {
            state.destination = action.payload; 
        },
        setTravelTimeInformation: (state, action) => {
            state.travelTimeInformation = action.payload; 
        },
    },
});

export const { setOrigin, setDestination, setTravelTimeInformation } = navSlice.actions;

export const selectOrigin = (state) => state.nav.origin;
export const selectDestination = (state) => state.nav.destination;
export const selectTravelTimeInformation = (state) => state.nav.travelTimeInformation;

export default navSlice.reducer;

CodePudding user response:

Issue

The origin state value is initially null.

const initialState = {
  origin: null, // <-- initially null here
  destination: null,
  travelTimeInformation: null
}

And the code is attempting to access into this null value.

const Map = () => {
  const origin = useSelector(selectOrigin);

  return (
    <MapView
      style={{flex:1, marginTop:10}}
      initialRegion={{
        latitude: origin.location.lat,
        longitude: origin.location.lng,
        latitudeDelta: 0.0922,
        longitudeDelta: 0.0421,
      }}
    />
  );
};

Solutions

You've a few options. Here are 4, there may be others.

  1. Conditionally render the MapView component on the origin state being populated.

    const Map = () => {
      const origin = useSelector(selectOrigin);
    
      return origin?.location
        ? (
          <MapView
            style={{flex:1, marginTop:10}}
            initialRegion={{
              latitude: origin.location.lat,
              longitude: origin.location.lng,
              latitudeDelta: 0.0922,
              longitudeDelta: 0.0421,
            }}
          />
        ) : null;
    };
    
  2. Use Optional Chaining operator on the origin access and provide a fallback value.

    const Map = () => {
      const origin = useSelector(selectOrigin);
    
      return (
        <MapView
          style={{flex:1, marginTop:10}}
          initialRegion={{
            latitude: origin?.location?.lat ?? 0,  // use fallback value that makes sense
            longitude: origin?.location?.lng ?? 0, // use fallback value that makes sense
            latitudeDelta: 0.0922,
            longitudeDelta: 0.0421,
          }}
        />
      );
    };
    
  3. Provide a valid, defined origin value from the selector.

    const defaultOrigin = { location: { lat: 0, lng: 0 } }; // use origin value that makes sense
    export const selectOrigin = (state) => state.nav.origin ?? defaultOrigin;
    
  4. Or just provide a more useful initial state value.

     const defaultOrigin = { location: { lat: 0, lng: 0 } }; // use origin value that makes sense
     const initialState = {
       origin: defaultOrigin,
       destination: null,
       travelTimeInformation: null
     }
    
  • Related