如何解决React useReducer:收到有效负载,状态未更新
我使用这个 article 来帮助使用 useReducer
钩子。
我创建了这个上下文组件,因为我正在使用 react-leaflet 路由机器来为路线创建标记,我想保存纬度和longitude 在本地存储中;我最初可以保存它们,但无法更新它们!
基本上在我的 UserContext
组件中,我创建了这个 reducer 函数:
function userReducer(state,{ type,payload }) {
switch (type) {
case 'isLengthOfMarkersLessthanTwoFalse': {
return {
...state,isLengthOfMarkersLessthanTwo: payload.isLengthOfMarkersLessthanTwo
};
}
case 'updateMarkers': {
console.log('type,payload ',type,payload);
return {
...state,...state.markers.map(element => {
console.log('element.alt === payload.alt ',element.alt === payload.alt);
return element.alt === payload.alt ? { ...element,...payload } : element;
})
};
}
default: {
throw new Error(`Unhandled action type: ${type}`);
}
}
}
所以你可以看到 case 子句中有一个 console.log
,
case 'updateMarkers': {
console.log('type,payload);
return {
...state,payload updateMarkers LatLng {lat: 40.74154270838886,lng: -73.76230053137989,alt: "current location"} alt: "current location"lat: 40.74154270838886lng: -73.76230053137989
所以它实际上IS在reducer中被传递了,但是状态没有被更新!
This is the complete component :
import React,{ useState,useEffect,useReducer } from 'react';
import { getUserAvatar } from '../../utils/index';
import { parse,stringify } from 'flatted';
var initialState = {
avatar: '/static/uploads/profile-avatars/placeholder.jpg',isRoutingVisible: false,removeRoutingMachine: false,isLengthOfMarkersLessthanTwo: true,markers: [],currentMap: {}
};
var UserContext = React.createContext();
function setLocalStorage(key,value) {
function isJson(item) {
item = typeof item !== 'string' ? JSON.stringify(item) : item;
try {
item = JSON.parse(item);
} catch (e) {
return false;
}
if (typeof item === 'object' && item !== null) {
return true;
}
return false;
}
try {
window.localStorage.setItem(key,JSON.stringify(value));
} catch (errors) {
// catch possible errors:
console.log(errors);
}
}
function getLocalStorage(key,initialValue) {
try {
const value = window.localStorage.getItem(key);
return value ? JSON.parse(value) : initialValue;
} catch (e) {
return initialValue;
}
}
function UserProvider({ children }) {
const [user,setUser] = useState(() => getLocalStorage('user',initialState));
const [isAvatarUploading,setIsAvatarUploading] = useState(true);
function userReducer(state,...payload } : element;
})
};
}
default: {
throw new Error(`Unhandled action type: ${type}`);
}
}
}
const [state,dispatch] = useReducer(userReducer,initialState);
// console.log('user ',user);
useEffect(() => {
setLocalStorage('user',user);
},[user]);
useEffect(() => {
console.log('user.isRoutingVisibile ',user.isRoutingVisibile);
},[user.isRoutingVisibile]);
useEffect(() => {
console.log('state',state);
if (user.markers.length === 2) {
dispatch({
type: 'isLengthOfMarkersLessthanTwoFalse',payload: { isLengthOfMarkersLessthanTwo: false }
});
}
},[JSON.stringify(user.markers)]);
useEffect(() => {
if (user.id) {
getUserAvatar()
.then(userAvatar => {
setIsAvatarUploading(false);
setUser(user => ({ ...user,avatar: userAvatar }));
})
.catch(err => console.log('error thrown from getUserAvatar',err));
} else {
console.log('No user yet!');
}
},[user.id]);
return (
<UserContext.Provider
value={{
userId: user.id,setUserId: id => setUser({ ...user,id }),userAvatar: user.avatar,setUserAvatar: avatar => setUser({ ...user,avatar }),isAvatarUploading: isAvatarUploading,userImages: user.images,setUserImages: images => setUser({ ...user,images }),userMarkers: user.markers,setUserMarkers: marker => {
state.isLengthOfMarkersLessthanTwo
? setUser(user => ({
...user,markers: [...user.markers,marker]
}))
: () => null;
},setUpdateUserMarker: dispatch,deleteUserMarkers: () => {
setUser({
...user,markers: [
...user.markers.filter(function(e,i,a) {
return e !== a[a.length - 1];
})
]
});
},setUserMarkersToNull: () =>
setUser({
...user,markers: null
}),userMap: user.currentMap,setUserCurrentMap: map =>
setUser({ ...user,currentMap: { ...user.currentMap,map } }),removeRoutingMachine: user.removeRoutingMachine,resetUserMarkers: () => {
console.log('fired setIsRoutingVisibiletoTrue');
setUser({
...user,removeRoutingMachine: true,markers: []
});
},isRoutingVisibile: user.isRoutingVisible,setIsRoutingVisibiletoTrue: () => {
console.log('fired setIsRoutingVisibiletoTrue');
setUser({
...user,isRoutingVisible: true
});
},setIsRoutingVisibiletoFalse: () => {
console.log('fired setIsRoutingVisibiletoFalse');
setUser({
...user,isRoutingVisible: false
});
}
}}
>
{children}
</UserContext.Provider>
);
}
export default UserContext;
export { UserProvider };
在路由机器中,我是这样称呼它的:
setUpdateUserMarker({
type: 'updateMarkers',payload: e.latlng
});
解决方法
在您的 case 'updateMarkers'
中,您正在映射 state.markers
数组,但您将其作为状态的顶级属性进行传播。这实际上将在您的状态上创建属性 0
、1
等,并且根本不会更新 markers
属性。
运行这个非常简化的版本,看看它做了什么。
const state = {markers: [1,2,3]};
console.log({...state,...state.markers});
您想要做的是用映射数组替换 markers
属性。
case 'updateMarkers': {
return {
...state,markers: state.markers.map(element => {
return element.alt === payload.alt ? { ...element,...payload } : element;
})
};
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。