首页 > 解决方案 > React Hooks:useEffect、useReducer、createContext 和 localStorage;TypeError:无法读取未定义的属性

问题描述

我在我的地图应用程序中使用本地存储来进行一些持久存储;还使用 React.createContext 和 useReducer 在组件之间共享和更新状态。

本地存储中的状态,以及控制台中的应用程序中的状态正在更新和呈现,即哈希生成的 id,来自 Cloudinary 的图像路径。

但是当我点击地图添加标记时,我得到:

TypeError:无法读取未定义的属性“标记”

这很奇怪,因为我在控制台和本地存储中看到了什么。

我的想法是我的接线错误。

我的 UserContext 组件:

var initialState = {
  avatar: '/static/uploads/profile-avatars/placeholder.jpg',
  id: null,
  isRoutingVisible: false,
  removeRoutingMachine: false,
  isLengthOfMarkersLessThanTwo: true,
  markers: [],
  currentMap: {}
};

var UserContext = React.createContext();

function UserProvider({ children }) {
  function userReducer(state, { type, payload }) {

    switch (type) {
      case 'setUserId': {
        return { ...state, ...{ id: payload.id } };
        }

      case 'setAvatar': {
        return {
          ...state,
          ...{ avatar: payload.avatar }
        };
      }

      case 'setIsRoutingVisible': {
        return {
          ...state,
          ...{ isRoutingVisible: payload.isRoutingVisible }
        };
      }

      case 'isLengthOfMarkersLessThanTwoFalse': {
        return {
          ...state,
          ...{
            isLengthOfMarkersLessThanTwo: payload.isLengthOfMarkersLessThanTwo
          }
        };
       
      }

      case 'addMarker': {
        user.isLengthOfMarkersLessThanTwo
          ? {
              ...state,
              markers: user.markers.concat(payload.marker)
            }
          : null;
        break;
      }
   
      default: {
        throw new Error(`Unhandled action type: ${type}`);
      }
    }
  }

  const [user, setUser] = useState(() => getLocalStorage('user', initialState));
  var [state, dispatch] = useReducer(userReducer, user);

  const [isAvatarUploading, setIsAvatarUploading] = useState(true);

  useEffect(() => {
    setLocalStorage('user', state);
  }, [state]);

  useEffect(() => {
    console.log('state', state);
    if (state.markers.length === 2) {
      dispatch({
        type: 'isLengthOfMarkersLessThanTwoFalse',
        payload: { isLengthOfMarkersLessThanTwo: false }
      });
    }
  }, [JSON.stringify(state.markers)]);

  useEffect(() => {
    console.log('state', state);

    if (state.id) {
      getUserAvatar()
        .then(userAvatar => {
          console.log('userAvatar ', userAvatar);
          setIsAvatarUploading(false);
          dispatch({
            type: 'setAvatar',
            payload: { avatar: userAvatar }
          });
        })
        .catch(err => console.log('error thrown from getUserAvatar', err));
    } else {
      console.log('No user yet!');
    }
  }, [state.id]);

  return (
    <UserContext.Provider
      value={{
        userId: state.id,

        userAvatar: state.avatar,

        dispatch: dispatch,

        isAvatarUploading: state.isAvatarUploading,

        userImages: state.images,

        userMarkers: state.markers,

        userMap: state.currentMap,

        removeRoutingMachine: state.removeRoutingMachine,

        isRoutingVisibile: state.isRoutingVisible
      }}
    >
      {children}
    </UserContext.Provider>
  );
}

export default UserContext;

export { UserProvider };

我想我需要一个自定义钩子,用来传递旧状态并用它来观察变化和更新它。

  var newUserState = initialState => {
    const [state, setState] = useState(initialState);
    var setter = useCallback(() => setState(state => !state), [setState]);
    return [state, setter];
  };


  var [newUserState, setter] = newUserState(state)

任何帮助将不胜感激!

标签: reactjslocal-storageuse-effectuse-contextuse-reducer

解决方案


在您的addMarker情况下,您可能想要访问局部state变量而不是全局变量user

另外,根据我对这个其他问题的答案的理解,您宁愿在组件之外定义减速器,因为当您重新定义减速器功能时,React 会触发一些不需要的更新。

这些是否能解决你的问题,我不能说......


推荐阅读