【问题标题】:How to type properly object initial value in React CreateContext如何在 React CreateContext 中正确键入对象初始值
【发布时间】:2021-11-02 22:11:22
【问题描述】:

我应该如何在 React Create Context 中正确输入 constance trainsDetails 的初始值,这是一个具有不同属性的对象。 TrainsDetails 是从端点获取的单个对象,其值在下面以 TrainsDetailsResponseType 类型提供:

type TrainsDetailsResponseType = {
    trainId: string;
    trainNo: string;
    lineId: string;
    route: string;
    lineKmPosition: string;
    speed: number;
    deviationFromTimetable: number;
    mileage: number;
    lastInspectionDate: string;
    nextInspectionDate: string;
    state: string;
};

这里是 TrainsContextValues 的接口:

interface TrainsContextValues {
    trainsList: TrainsListResponseType[];
    trainsDetails: TrainsDetailsResponseType;
    handlePushToTrainsDetails: (arg: string) => void;
    trainId: string;
}

我应该如何正确输入 trainsDetails 的初始值?

export const TrainsContext = createContext<TrainsContextValues>({
    trainsList: [],
    trainsDetails: ,
    handlePushToTrainsDetails: () => undefined,
    trainId: '',
});

在这里你也可以看到我是如何在 useState 钩子中输入 trainsDetails 的

 const [trainsDetails, setTrainsDetails] = useState<TrainsDetailsResponseType>();

【问题讨论】:

    标签: reactjs typescript react-context


    【解决方案1】:

    正如您在示例中看到的,状态值类型是TrainsDetailsResponseType | undefined

    // typeof trainsDetails = TrainsDetailsResponseType | undefined
    const [trainsDetails, setTrainsDetails] = useState<TrainsDetailsResponseType>();
    

    您可以在 React 上下文值中为 trainsDetails 指定类似的类型:

    interface TrainsContextValues {
      trainsList: TrainsListResponseType[];
    
      // optional type (?) or TrainsDetailsResponseType | undefined
      trainsDetails?: TrainsDetailsResponseType;
    
      handlePushToTrainsDetails: (arg: string) => void;
      trainId: string;
    }
    
    export const TrainsContext = React.createContext<TrainsContextValues>({
      trainsList: [],
      trainsDetails: undefined,
      handlePushToTrainsDetails: () => undefined,
      trainId: "",
    });
    

    这是正确的,因为在您从端点获取之前,您确实没有 trainsDetails 的数据。


    已更新。长答案

    传递给createContext 的参数不是上下文的initialValue,而是defaultValue,这一点很重要。 defaultValue 参数仅在树中组件上方没有匹配的 Provider 时使用。

    你有两种使用上下文的场景:

    1. - 您允许使用上下文,直到收到所有必要的数据。在这种情况下,如果没有数据,您应该提供备用:

    interface TrainsContextValues {
      trainsList: TrainsListResponseType[];
      trainsDetails?: TrainsDetailsResponseType;
      handlePushToTrainsDetails: (arg: string) => void;
      trainId: string;
    }
    
    export const TrainsContext = React.createContext<TrainsContextValues>({
      trainsList: [],
      trainsDetails: undefined,
      handlePushToTrainsDetails: () => {},
      trainId: "",
    });
    
    const Parent = () => {
      const [trainsDetails, setTrainsDetails] =
        useState<TrainsDetailsResponseType>();
    
      useEffect(() => {
        const getTrainsDetail = async () => {
          try {
            const response = await fetch("your-api");
            const data: TrainsDetailsResponseType = await response.json();
    
            setTrainsDetails(data);
          } catch {
            // your logic for the failed request
          }
        };
    
        getTrainsDetail();
      }, []);
    
      const contextValue = useMemo(
        () => ({
          // undefined | data from api
          trainsDetails,
    
          // replace to actually
          trainsList: [],
          handlePushToTrainsDetails: () => {},
          trainId: "",
        }),
        [trainsDetails]
      );
    
      return (
        <TrainsContext.Provider value={contextValue}>
          <Child />
        </TrainsContext.Provider>
      );
    };
    
    const Child = () => {
      const { trainsDetails } = useContext(TrainsContext);
    
      // technically, the component can be rendered out of context and it should be ready for this
      if (!trainsDetails) {
        return <FallbackComponent />;
      }
    
      return <TrainsDetailsComponent data={trainsDetails} />;
    };
    

    2. - 您不允许在没有真实数据的情况下使用上下文。 WARNING - 这是一个非常严格的模式,它仅在应用程序不能不应该使用没有真实数据的上下文时使用:

    interface TrainsContextValues {
      trainsList: TrainsListResponseType[];
      trainsDetails: TrainsDetailsResponseType;
      handlePushToTrainsDetails: (arg: string) => void;
      trainId: string;
    }
    
    export const TrainsContext = React.createContext<TrainsContextValues | null>(
      null
    );
    
    const useTrainsContext = (): TrainsContextValues => {
      const data = useContext(TrainsContext);
    
      if (!data) {
        throw new Error("could not find trains context value");
      }
    
      return data;
    };
    
    const Parent = () => {
      const [trainsDetails, setTrainsDetails] =
        useState<TrainsDetailsResponseType>();
    
      useEffect(() => {
        const getTrainsDetail = async () => {
          try {
            const response = await fetch("your-api");
            const data: TrainsDetailsResponseType = await response.json();
    
            setTrainsDetails(data);
          } catch {
            // your logic for the dropped request
          }
        };
    
        getTrainsDetail();
      }, []);
    
      const contextValue = useMemo(
        () =>
          trainsDetails
            ? {
                trainsDetails,
                trainsList: [],
                handlePushToTrainsDetails: () => {},
                trainId: "",
              }
            : null,
        [trainsDetails]
      );
    
      if (!contextValue) {
        // some fallback for empty trainsDetails
        return <Loading />;
      }
    
      return (
        <TrainsContext.Provider value={contextValue}>
          <Child />
        </TrainsContext.Provider>
      );
    };
    
    const Child = () => {
      const { trainsDetails } = useTrainsContext();
    
      return <TrainsDetailsComponent data={trainsDetails} />;
    };
    

    第二种情况是特定的,仅在上下文中缺少数据是组件组合中的逻辑错误时使用。并且用户无法纠正这种情况。例如,redux 中缺少 store 提供程序。

    【讨论】:

    • 您好,谢谢。当我输入你的 cmets 时,当我想从对象 trainsDetails 中提取特定道具时,我也会遇到打字稿错误。它在使用数据的组件中: Object is possible is 'undefined'.ts(2532) const trainsDetails: TrainsDetailsResponseType |未定义
    • @marcinb1986 你好!我已经更新了答案。请看一下,希望对你有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-22
    • 1970-01-01
    相关资源
    最近更新 更多