使用 UseReducer 和 useContext 挂钩进行调度:类型 {} 上不存在调度

dispatch with UseReducer and useContext hooks: dispatch does not exist on type {}

我正在尝试使用 React 构建一个小型 Cesium 应用程序,它可以通过单击与每个位置相关联的按钮缩放到地球上的各个地方。我正在使用 useContext 和 useReducer 挂钩设置减速器,但我遇到了一个我无法弄清楚的调度问题,到目前为止还没有找到任何指向我的问题的东西可能。到目前为止,我看过的所有页面都告诉我,我所拥有的应该可以工作,但我显然遗漏了一些东西。

下面是我正在使用的两个文件:

位置-card.tsx

export function LocationCard(props: LocationCardProps) {
  const classes = useStyles();
  const { className, name, type, location, onDetails } = props;

  const { dispatch } = useMapViewerContext();

  return (
    <Card variant="outlined" className={classes.locationCard}>
      <div className={classes.locationDetails}>
        <CardContent className={classes.locationContent}>
          <Typography component="div" variant="subtitle2">
            {name}
          </Typography>
          <Typography variant="caption" color="textSecondary">
            {type}
          </Typography>
        </CardContent>
        <div className={classes.locationCardControls}>
          <Tooltip title="Zoom to Location">
            <IconButton
              aria-label="Zoom To Location"
              onClick={() => {dispatch(zoomToLocation(location))}}
              className={classes.locationButton}
            >
.....

上述文件还有更多内容,但这是相关的部分。我得到的错误是我尝试设置调度的地方。有人告诉我

Property 'dispatch' does not exist on type '{}'

地图查看器-context.tsx

import React, { useContext, useReducer, useState } from 'react';
import Cartesian3 from 'cesium/Source/Core/Cartesian3';
import { Context } from 'node:vm';

export interface MapViewerState {
  location: Cartesian3;
  isCameraFlyTo: boolean;
  zoomToLocation: (value: Cartesian3) => void;
}

const initialState: MapViewerState = {
  location: Cartesian3.fromDegrees(
    -95.96044633079181,
    41.139682398924556,
    2100
  ),
  isCameraFlyTo: false,
  zoomToLocation: undefined,
};

export const MapViewerContext = React.createContext();

// Actions
export const ZOOM_TO_LOCATION = "ZOOM_TO_LOCATION";
export const COMPLETE_ZOOM = "FINISH";

// Action creators
export const zoomToLocation = (value: Cartesian3) => {
  return { type: ZOOM_TO_LOCATION, value };
}

// Reducer
export const mapViewerReducer = (state, action): MapViewerState => {
  switch (action.type) {
    case ZOOM_TO_LOCATION:
      return {...state, location: action.value, isCameraFlyTo: true};
    case COMPLETE_ZOOM:
      return {...state, isCameraFlyTo: false}
    default:
      return state;
  }
}

const MapViewerProvider = (props) => {
  const [state, dispatch] = useReducer(mapViewerReducer, initialState);

  const mapViewerData = { state, dispatch };

  return <MapViewerContext.Provider value={mapViewerData} {...props} />;
};

const useMapViewerContext = () => {
  return useContext(MapViewerContext);
};

export { MapViewerProvider, useMapViewerContext };

这里是我设置动作、reducer 和上下文的地方。我也有一个问题 React.createContext() 没有争论。我可以通过为它提供我定义的 initialState 来消除该错误,但是 location-card.tsx 中的错误只是改变了至:

Property 'dispatch' does not exist on type 'MapViewerState'.

谁能帮我弄清楚如何让它工作?到目前为止我尝试过的一切都失败了。

您看到的错误是由于 createContext 没有正确推断您的上下文类型造成的。您可以像这样明确指定上下文的类型:

export interface MVContext {
  state: MapViewerState;
  dispatch: (action: MapViewerAction) => void;
}

export const MapViewerContext = createContext<MVContext>({} as MVContext);

只要您不打算在上下文提供程序之外使用 useContext,类型强制 {} as MVContext 就是安全的。如果是,则需要为每个键提供默认值:

export const MapViewerContext = createContext<MVContext>({
  state: MapViewerState.Default,
  dispatch: () => {},
});

您为 map-view-context 编写的代码很有趣。我把它提取出来供我通读。

1 export const MapViewerContext = React.createContext();

2 const MapViewerProvider = (props) => {
3  const [state, dispatch] = useReducer(mapViewerReducer, initialState);

4  const mapViewerData = { state, dispatch };

5  return <MapViewerContext.Provider value={mapViewerData} {...props} />;
6 };

7 const useMapViewerContext = () => {
8   return useContext(MapViewerContext);
9 };

10export { MapViewerProvider, useMapViewerContext };

我假设您的代码用法如下。

  <MapViewerProvider>
    <Children />
  </MapViewerProvider>

  const Children = () => {
    const { state, dispatch } = useMapViewerContext()
  }

你可以这样试试吗

  <MapViewerContext.Provider value={useReducer(..., ...)}>
     <Children />
  <MapViewerContext.Provider />
  
  const Children = () => {
    const [ state, dispatch ] = useContext(MapViewerContexxt)
  }

我知道这和你做的很相似。我将 {} 更改为 [] 而没有添加另一个临时变量。因为我的直觉是这条线,LINE 4.

 const mapViewerData = { state, dispatch };

每次进入此渲染时,您都会以某种方式获得 value 的新实例。