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 数组,但您将其作为状态的顶级属性进行传播。这实际上将在您的状态上创建属性 01 等,并且根本不会更新 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;
    })
  };
}

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...