reactjs - React useReducer:收到有效负载,状态未更新
问题描述
我正在使用这篇文章来帮助使用useReducer
钩子。
我创建了这个上下文组件,因为我正在使用react-leaflet路由机器为路线创建标记,并且我想将纬度和经度保存在本地存储中;我最初可以保存它们,但我无法更新它们!
基本上在我的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}`);
}
}
}
所以你可以看到有一个console.log
in case 子句,
case 'updateMarkers': {
console.log('type, payload ', type, payload);
return {
...state,
type, payload updateMarkers LatLng {lat: 40.74154270838886, lng: -73.76230053137989, alt: "current location"} alt: "current location"lat: 40.74154270838886lng: -73.76230053137989
所以它实际上是在减速器中传递,但状态没有被更新!
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, { 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}`);
}
}
}
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,
isRoutingVisible: false,
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
数组,但您将其作为状态的顶级属性进行传播。这实际上会在您的状态上创建 properties 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;
})
};
}
推荐阅读
- tableau-api - 混合 lod 和 non-lod 计算
- sqlite - 如何在 SQLite 触发器中使用 WITH 子句
- python - 在一行中加入不重复的行 - python
- java - Hybris Item:自定义属性和属性之间的区别
- javascript - React setState 不更新缩减数组
- markdown - Jekyll:显示不同类别的帖子
- json - 使用自定义 MarshalJSON 更改结构中的 JSON 标记
- java - 为什么这个while循环条件为真
- java - 如何将 ISO 8601 格式的 DateTime 转换为 Java 中的另一个时区?
- javascript - 基于javascript中字符串中间的文本对数组进行排序