You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native+Redux项目中reducer不生效、setOrigin不是函数如何解决?

Redux实现地图功能报错解决方案

问题背景

跟着视频教程学习Redux,打算实现地图功能,在reducer内封装了setOrigin、setDestination、setTravelTimeInformation方法搭建数据层,运行时出现两处报错。

相关代码

import {createSlice} from "@reduxjs/toolkit"; 

const initialState = {
    origin: 0, 
    destination: 0, 
    travelTimeInformation: 0, 
}; 
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;

// selectors 
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; // connects us to the store

Map.js

import React from 'react'
import { StyleSheet, Text, View } from 'react-native'
import MapView  , { Marker } from "react-native-maps"; 
import tw from "tailwind-react-native-classnames"; 
import { useSelector } from 'react-redux';
import { selectOrigin } from '../slices/navSlice';

const Map = () => {
    // this hook takes a selector function as an argument
    const origin = useSelector(selectOrigin); // it is an object (returns null and it causes to error rn )
    return (
          <MapView
                style = {tw`flex-1`}
                mapType = "mutedStandart"
                initialRegion={{ // info about the location we chose
                latitude: origin.location.lat,
                longitude: origin.location.lng,
                latitudeDelta: 0.005,
                longitudeDelta: 0.005,
                }}
         />

    )
}

export default Map

const styles = StyleSheet.create({})

HomeScreen.js

import React from 'react'
import { StyleSheet, Text, View, SafeAreaView, Image} from 'react-native'
import tw from "tailwind-react-native-classnames"; 
import NavOptions from '../Components/NavOptions';
import { GooglePlacesAutocomplete } from 'react-native-google-places-autocomplete';
import {GOOGLE_MAPS_APIKEY} from "@env";  
import { useDispatch } from 'react-redux';
import {setDestination, setOrigin} from "../slices/navSlice"; 

const HomeScreen = () => {
    const dispatch = useDispatch(); 
    return (
        <SafeAreaView style = {tw`bg-white h-full`}>
            <View style = {tw`p-10`}>
                <Image
                    style = {{
                        width: 100, height: 100, resizeMode: "contain",
                    }}
                    source = {{
                        uri: "data:image/png;base64,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"
                    }}
                />
                <GooglePlacesAutocomplete
                    placeholder =  "Where from?"  
                    styles = {{
                        container: {
                            flex: 0, 

                        }, 
                        textInput: {
                            fontSize: 18,
                        }, 
                    }}
                    onPress = {(data, details = null) => {
                        // details include infos like coordinates etc.
                        dispatch(setOrigin({
                            location: details.geometry.location,
                            description: data.description
                        }))

                        dispatch(setDestination(null)); 
                        
                        // console.log(details); 
                    } }
                    fetchDetails = {true}
                    returnKeyType = {"search"}
                    enablePoweredByContainer = {false}
                    minLength = {2}
                    query = {{
                        key: GOOGLE_MAPS_APIKEY, 
                        language: "en", 

                    }}
                    nearbyPlacesAPI = "GooglePlacesSearch"
                    debounce = {400}
                />
                <NavOptions/>
            </View> 
        </SafeAreaView>
    )
}

export default HomeScreen

const styles = StyleSheet.create({})

store.js

import { configureStore } from '@reduxjs/toolkit'; 
import navReducer from "./slices/navSlice"; 

export default configureStore({
  reducer: {
    nav: navReducer,
  },
})

报错信息

  • dispatch调用setOrigin时报错:setOrigin is not a function
  • Map.js中读取origin的location经纬度属性报错,useSelector返回的origin不是预期对象

终端错误日志:

(0, _navSlice.setOrigin) is not a function. (In '(0, _navSlice.setOrigin)({
          location: details.geometry.location,
          description: data.description
        })', '(0, _navSlice.setOrigin)' is undefined)

根因定位

navSlice.js中createSlice的配置项键名拼写错误,Redux Toolkit要求定义reducer集合的字段是reducers(末尾带s),而非reducer。拼写错误导致createSlice没有生成对应的action方法,所以导出的setOrigin为undefined,调用时报错。同时因为action未正常触发,origin始终是初始值0,读取location属性自然报错。

修复方案

第一步:修正navSlice.js的配置

将createSlice配置中的reducer:改为reducers:,修改后对应片段如下:

export const navSlice = createSlice({
    name: "nav", 
    initialState, 
    reducers: { // 此处新增s,修正拼写
        setOrigin: ( state, action ) => {
            state.origin = action.payload; 
        },
        setDestination: (state, action) => {
            state.destination = action.payload; 
        },
        setTravelTimeInformation: (state, action) => {
            state.travelTimeInformation = action.payload; 
        },
    },
});

第二步:优化Map.js的空值判断

初始状态下origin还未被赋值,直接读取origin.location会报错,建议增加空值判断,只有origin存在且包含location属性时再渲染地图:

const Map = () => {
    const origin = useSelector(selectOrigin);
    // 增加空值拦截
    if (!origin?.location) return null;
    return (
          <MapView
                style = {tw`flex-1`}
                mapType = "mutedStandart"
                initialRegion={{
                latitude: origin.location.lat,
                longitude: origin.location.lng,
                latitudeDelta: 0.005,
                longitudeDelta: 0.005,
                }}
         />
    )
}

内容的提问来源于stack exchange,提问作者OzzyOsbourne

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 06:42:01