在useEffect和useSelector中未定义redux状态



我是redu的新手。目前我正在做一个项目,通过API调用在地图上显示附近的自行车站。所以这意味着大多数redux操作都是异步的,并在另一个操作中为下一个api调用返回一些数据。当我在useEffect中调度所有操作并使用useSelector执行状态时,它在第一次渲染时显示它们,刷新后返回未定义的这是我在使用redux、redux-thunk、useEffect、useSelector时会遇到的常见问题。

我在useEffect钩子中尝试了异步函数,以等待每个操作调用完成

操作:

export const fetchIPLocation = () => {
return async (dispatch) => {
try {
let response = await fetch(`https://ip.nf/me.json`)
if(response.ok) {
let data = await response.json()
dispatch({
type: FETCH_IP_LOCATION,
payload: data.ip.ip
})
}
} catch (error) {

}
}
}
export const fetchUserData = (IPadress) => {
return async (dispatch) => {
try {
let response = await fetch(`http://api.ipstack.com/${IPadress}?access_key=15633b167163620b5cd84ef60db62414`)
if(response.ok) {
let data = await response.json()
dispatch({
type: FETCH_USER_DATA,
payload: data
})
}
} catch (error) {
console.log(error)
}
}
}

减速器:

import { initialState } from "../store";
import { FETCH_IP_LOCATION, FETCH_USER_DATA, FETCH_NETWORKS } from "../action";
export const rootReducer = (state = initialState, action) => {
switch (action.type) {
case FETCH_IP_LOCATION:
return {
...state,
ipLocation: action.payload,
isLoading: false,
}
case FETCH_USER_DATA:
return {
...state,
userData: action.payload,
isLoading: false,
}
case FETCH_NETWORKS: 
return {
...state,
isLoading: false,
bikeNetworks: action.payload,
}
}
}

MapComponent.jsx,它渲染传单地图并使用所有状态

import React, { useState } from 'react';
import '../styles/MapComponent.css';
import { MapContainer, TileLayer, Marker, Popup } from 'react-leaflet';
import { useEffect } from 'react';
import { fetchIPLocation, fetchUserData, getUserData } from '../redux/action/';
import { useDispatch, useSelector } from 'react-redux'

const MapComponent = () => {
const dispatch = useDispatch()
const [latitude, setLatitude] = useState(0)
const [longitude, setLongitude] = useState(0)
const [checkCords, setCheckCords] = useState(false)
const ipLocation = useSelector((state) => state.ipLocation)
const userCountry = useSelector((state) => state.userData.country_code)

console.log(userCountry)

useEffect(() => {
if(navigator.geolocation) {
navigator.geolocation.watchPosition((position) => {
setLatitude(position.coords.latitude)
setLongitude(position.coords.longitude)
setCheckCords(true)
})
}
}, [])
useEffect(async () => {
await dispatch(fetchIPLocation())
await dispatch(fetchUserData(ipLocation))
}, [])
return (
!checkCords ? <h1>Loading...</h1> :
<MapContainer center={[latitude, longitude]} zoom={11}>
<TileLayer
attribution='&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
<Marker position={[latitude, longitude]}>
<Popup>
A pretty CSS3 popup. <br /> Easily customizable.
</Popup>
</Marker>
</MapContainer>

)
}
export default MapComponent

冗余存储:

import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import persistStore from 'redux-persist/es/persistStore';
import storage from 'redux-persist/lib/storage';
import persistReducer from 'redux-persist/es/persistReducer';
import { rootReducer } from '../reducer';
export const initialState = {
ipLocation: [],
userData: [],
bikeNetworks: [],
bikeStations: [],
isLoading: true,
}
const persistConfig = {
key: 'root',
storage
}
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose
const persistedReducer = persistReducer(persistConfig, rootReducer)
const configureStore = createStore(
persistedReducer,
initialState,
composeEnhancers(applyMiddleware(thunk))
)
const persistor = persistStore(configureStore)
export { configureStore, persistor }

app.js和提供程序:

import './App.css';
import 'bootstrap/dist/css/bootstrap.min.css';
import MapComponent from './components/MapComponent'
import { configureStore, persistor } from './redux/store';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/integration/react';
import { BrowserRouter,  Routes, Route } from 'react-router-dom';
import {Container, Row, Col} from 'react-bootstrap';

const App = () => {
return (
<Provider store={configureStore}>
<PersistGate persistor={persistor} loading={null}>
<Container fluid={true} className='px-0 overflow-hidden'>
<BrowserRouter>
<Row>
<Col md={12}>
<Routes>
<Route exact path='/' element={<MapComponent />} />
</Routes>
</Col>
</Row>
</BrowserRouter>
</Container>
</PersistGate>
</Provider>
);
}
export default App;

MapComponent.jsxuseSelector中,ipLocation在第一个函数(即fetchIPLocation()(之后和第二个函数(如fetchUserData()(之前不会更新。

您要做的是在从Actions文件中的操作fetchIPLocation获得响应后调度操作fetchUserData(ipLocation)

// Action
export const fetchIPLocation = () => {
return async (dispatch) => {
try {
let response = await fetch(`https://ip.nf/me.json`)
if(response.ok) {
let data = await response.json()
dispatch({
type: FETCH_IP_LOCATION,
payload: data.ip.ip
})
dispatch(fetchUserData(data.ip.ip)
}
} catch (error) {

}
}
}

MapComponent.jsx的使用效果中,只需调用dispatch(fetchIPLocation())

最新更新