如何使用React和TypeScript在函数中调用useContext?

时间:2020-07-17 11:24:29

标签: reactjs typescript

我已经定义了如下上下文来设置状态,就像下面一样,

"[markdown]": {
  "editor.wordWrap": "on",
  "editor.wrappingIndent": "indent",
  "editor.tabSize": 2
},

我在如下两个组件Uploadbutton和userbutton中使用此上下文,

interface DialogsCtxState {
    isDialogOpen: boolean;
    setIsDialogOpen: React.Dispatch<React.SetStateAction<boolean>>;
    itemVisible: boolean;
    setItemVisible: React.Dispatch<React.SetStateAction<boolean>>;
}

const initialState: DialogsCtxState = {
    isDialogOpen: false,
    setIsDialogOpen: () => {},
    itemVisible: false,
    setItemVisible: () => {},
};

export const DialogsContext = React.createContext<
    DialogsCtxState
>(initialState);

export const DialogsContextProvider: React.FC = ({ children }) => {
    const [isDialogOpen, setIsDialogOpen] = React.useState<boolean>(
        false
    );
    const [itemsVisible, setItemsVisible] = React.useState<boolean>(
        false
    );

    return (
        <DialogsContext.Provider
            value={{
                isDialogOpen,
                setIsDialogOpen,
                itemVisible,
                setItemVisible,
            }}
        >
            {children}
        </DialogsContext.Provider>
    );
};

以上代码片段效果很好。但是我想使用onUpload和onAdd方法将代码移到DialogContext文件中,其结果如下所示,

function UploadButton() {
    const {isDialogOpen, setIsDialogOpen, itemVisible, setItemVisible} = 
    React.useContext(DialogContext);
    const onUpload = () => {
        itemVisible && setItemVisible(false);
        setIsDialogOpen(isDialogOpen => !isDialogOpen);
    }
    return (
        <Button onClick={onUpload}/>
    );
}

function UserButton() {
    const {isDialogOpen, setIsDialogOpen, itemVisible, setItemVisible} = 
    React.useContext(DialogContext);
    const onAdd = () => {
        isDialogOpen && setIsDialogOpen(false);
        setItemVisible(prev => !prev);
    }
    return (
        <Button onClick={onAdd}/>
    );
}

我尝试过的,

在包含DialogContext的文件中,我尝试了以下类似操作

const onAdd = () => {
    function1(); //where thiscontains the code in onAdd before snippet.
}

const onUpload = () => {
    function2();//where this contains code in onUpload snippet before
}

但是我得到了错误react.usecontext用于一个既不是React函数组件也不是自定义react钩子的函数中。

我该如何解决。有人可以帮我解决这个问题。谢谢。

1 个答案:

答案 0 :(得分:0)

看起来从上下文返回的值的唯一用途是创建onUploadonAdd函数。在DialogsContextProvider组件中创建函数以将其作为值传递是一种更好的方法。例子

// context
interface DialogsCtxState {
   onUpload: () => void;
   onAdd: () => void;
};

const initialState: DialogsCtxState = {
   onUpload: () => {},
   onAdd: () => {}
};

export const DialogsContext = React.createContext<
    DialogsCtxState
>(initialState);

DialogsContextProvider组件

// context provider
export const DialogsContextProvider: React.FC = ({ children }) => {
    const [isDialogOpen, setIsDialogOpen] = React.useState<boolean>(
        false
    );

    const [itemsVisible, setItemsVisible] = React.useState<boolean>(
        false
    );

    // onUpload function
    const onUpload = useCallback(() => {
        itemsVisible && setItemsVisible(false);
        setIsDialogOpen((isDialogOpen) => !isDialogOpen);
    }, [itemsVisible]);

    // onAdd function
    const onAdd = useCallback(() => {
        isDialogOpen && setIsDialogOpen(false);
        setItemsVisible((prev) => !prev);
    }, [isDialogOpen]);

    return (
        <DialogsContext.Provider value={{ onAdd, onUpload}}>
            {children}
        </DialogsContext.Provider>
    );
};

这就是如何在UploadButtonUserButton组件中使用它的方法,

const UserButton: React.FC = () => {
   const { onAdd } = React.useContext(DialogsContext)
  
   // rest of the logic
}

const UploadButton: React.FC = () => {
   const { onUpload } = React.useContext(DialogsContext)
  
   // rest of the logic
}

注意,您的代码中存在多种错别字,因此如果您忽略采用自定义函数方法时发生的错误,因为useContext仅可用于功能组件< / strong>和自定义挂钩。要解决此问题,您必须采用自定义挂钩方法。例如

export const useOnUpload = () => {
  const { isDialogOpen, setIsDialogOpen, itemsVisible, setItemsVisible,
  } = React.useContext(DialogsContext);

  const onUpload = useCallback(() => {
    itemsVisible && setItemsVisible(false);
    setIsDialogOpen((isDialogOpen) => !isDialogOpen);
  }, [itemsVisible, setIsDialogOpen, setItemsVisible]);

  return onUpload;
};

// usage
function UploadButton() {
   const onUpload = useOnUpload();

   // rest of the logic
}

// similarly you can create the onUseAdd hook