【问题标题】:React useContext problem with Typescript -- any alternative to <Partial>?用 Typescript 反应 useContext 问题——<Partial> 的任何替代方案?
【发布时间】:2021-07-14 21:17:07
【问题描述】:

我有一个使用 useContext 的 React 应用程序,但我无法正确输入上下文。这是我所拥有的:

import React, { useState, createContext } from 'react';
import endpoints from '../components/endpoints/endpoints';

interface contextTypes {
    endpointQuery: string,
    setEndpointQuery: React.Dispatch<React.SetStateAction<string>>,
    searchInput: string,
    setSearchInput: React.Dispatch<React.SetStateAction<string>>,
    filmSearch: string | undefined,
    setFilmSearch: React.Dispatch<React.SetStateAction<string>>
    pageIndex: number,
    setPageIndex: React.Dispatch<React.SetStateAction<number>>,
    resetState: () => void;
}

export const DisplayContext = createContext<Partial<contextTypes>>({});

interface Props {
    children: React.ReactNode;
}

const DisplayContextProvider = (props: Props) => {
    const { nowShowing } = endpoints;
    const [ endpointQuery, setEndpointQuery ] = useState(nowShowing);
    const [ searchInput, setSearchInput ] = useState('');
    const [ filmSearch, setFilmSearch ] = useState('');
    const [ pageIndex, setPageIndex ] = useState(1);

    const resetState = () => {
        setSearchInput('');
        setFilmSearch('');
        setPageIndex(1);
    };

    const values = {
        endpointQuery,
        setEndpointQuery,
        pageIndex,
        setPageIndex,
        filmSearch,
        setFilmSearch,
        searchInput,
        setSearchInput,
        resetState
    };
    
    return (
        <DisplayContext.Provider value={values}>
            {props.children}
        </DisplayContext.Provider>
    );
};

export default DisplayContextProvider;

问题是,当我使用 &lt;Partial&lt;contextTypes&gt;&gt; 时,我的整个应用程序都会出现此错误:

Cannot invoke an object which is possibly 'undefined'

有没有办法解决这个问题,所以我不必到处添加! 标记到我得到未定义错误的所有内容? (我对 Typescript 也很陌生,所以我完全有可能以完全错误的方式输入我的上下文)

【问题讨论】:

  • createContext&lt;contextTypes&gt;({} as contextTypes); ?
  • Partial 表示缺少某些键并且不知道哪些键。所以 !需要,或者最好检查是否定义了密钥。如果不是这样,请不要使用 Partial。
  • @Adam Mann,为什么不存储一个初始状态以传递给具有相同形状(而不是 Partial)的 createContext?这样,已知形状中的每个属性都已定义。
  • @NadiaChibrikova,哇,这很管用。看起来很简单,但是as 让我很吃惊,因为我从来没有使用过那种语法。我想我需要深入研究如何使用它。
  • @AdamMann as 类似于 '!',带有 '!'你告诉 TS “我知道它不为空”,并用 as - “我知道它是 X 类型,即使它看起来不像”。如果您确信上下文将在使用之前被初始化,您也可以假装它已经初始化:)

标签: reactjs typescript react-context


【解决方案1】:

我认为问题在于您无法使用有用的默认值初始化上下文,但您希望上下文提供者在组件树中始终处于较高位置。

当我处于这种情况时,我想要以下行为:

  • 如果一个组件尝试使用consume context,但是provider没有在它上面使用,抛出一个错误
  • 使用上下文的组件应假定上下文已设置。

所以,我通常会创建一个钩子来包装 useContext 并为我进行 null 检查。

import React, { useContext, createContext } from 'react';

interface contextTypes {
    // ...
}

// private to this file
const DisplayContext = createContext<contextTypes | null>(null);

// Used by any component that needs the value, it returns a non-nullable contextTypes
export function useDisplay() {
  const display = useContext(DisplayContext);
  if (display == null) {
    throw Error("useDisplay requires DisplayProvider to be used higher in the component tree");
  }
  return display;
}

// Used to set the value. The cast is so the caller cannot set it to null,
// because I don't expect them ever to do that.
export const DisplayProvider: React.Provider<contextTypes> = DisplayContext.Provider as any;

如果在组件树中没有DisplayProvider 的组件中使用useDisplay,它将抛出并且组件不会挂载。

【讨论】:

  • 这是我认为的最佳实践,它已经使我们免于调试几次。
  • 我之前实际上使用过export const DisplayContext = createContext&lt;contextTypes | null&gt;(null);,但我的组件中不断收到错误...does not exist on type 'contextTypes | null'。也许是因为我设置的提供者与您在这里不同?带有 React 的 Typescript 似乎有很多怪癖,我觉得我在反复试验
  • 我猜你在验证结果是否为非空之前使用了 useContext(DisplayContext) 的结果,这可以解释 TypeScript 抱怨的原因。这就是 useDisplay 函数所做的,它检查 null 并抛出,所以你的组件不必这样做。这不是一个怪癖或错误:您可以尝试使用 DisplayContext 而无需在上面设置 DisplayContext.Provider 的其他组件,因此 TypeScript 强制您证明该值是非空。
猜你喜欢
  • 2012-04-27
  • 2011-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-13
  • 2014-12-27
  • 1970-01-01
相关资源
最近更新 更多