【问题标题】:dispatch with UseReducer and useContext hooks: dispatch does not exist on type {}使用 UseReducer 和 useContext 挂钩调度:类型 {} 上不存在调度
【发布时间】:2021-08-08 03:33:19
【问题描述】:

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

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

location-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}
            >
.....

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

类型“{}”上不存在属性“dispatch”

ma​​p-viewer-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 中的错误只是更改为:

“MapViewerState”类型上不存在属性“dispatch”。

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

【问题讨论】:

    标签: reactjs typescript use-context use-reducer createcontext


    【解决方案1】:

    您看到的错误是由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: () => {},
    });
    

    【讨论】:

      【解决方案2】:

      您为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)
        }
      

      我知道这与您所做的非常相似。我将{} 更改为[] 而不添加另一个临时变量。因为我的直觉是这条线,第 4 行。

       const mapViewerData = { state, dispatch };
      

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

      【讨论】:

        猜你喜欢
        • 2020-09-01
        • 2020-10-18
        • 2020-11-18
        • 2021-02-28
        • 2019-12-09
        • 1970-01-01
        • 2022-01-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多