【问题标题】:How to properly use React Context Provider with Typescript?如何正确使用带有 Typescript 的 React Context Provider?
【发布时间】:2021-05-18 17:09:03
【问题描述】:

我已经持续了好几个小时,试图寻找一些我认为可行但无法做到的东西。你能帮我解决这个问题吗?

我在这里有我的文件浏览器上下文,我想将 folderData 传递给另一个函数。

import { createContext, useContext } from 'react';

export interface fileBrowserContext {
  folderData: string;
}

export const FileBrowserContext = createContext<fileBrowserContext>({
  folderData: '',
});

export const useFileBrowserContext = () => useContext(FileBrowserContext);

这是我使用它的组件。我也在使用 react-hook-form,当我单击提交按钮时它正在工作。

    const FileBrowser = () => {

      const { control, watch, handleSubmit, register, reset, errors } = useForm({
        reValidateMode: 'onChange',
        defaultValues: {
          createFolder: '',
        },
      });

      const [folderData, setFolderData] = useState<string>('');

      async function onSubmit(formData: any) {
          if (Object.keys(errors).length === 0) {
            /* Create folder */
            setFolderData(formData.createFolder);

            reset({ createFolder: '' });
          }

          handleToastSuccess({
            message: 'Folder Created',
          });
      }


      function renderForm() {
         return (
          <Form onSubmit={handleSubmit(onSubmit)} className="CreateFolderForm">
            <Form.Group>
              <Form.Label>Create Folder</Form.Label>
              <Form.Control
                id="createFolder"
                name="createFolder"
                ref={register({
                  required: {
                    value: true,
                    message: 'This field is required.',
                  },
                })}
              />
            </Form.Group>

              <Button
                variant="contained"
                color="primary"
                type="submit"
              >
                Create
              </Button>
          </Form>
        );
      }

      const {
        isCreateFolderOpen,
        setIsCreateFolderOpen,
        handleFileCallback,
      } = useFileActionHandler(
        createFolder,
      );

      return (
        <FileBrowserContext.Provider value={{ folderData: folderData }}>
         <>
         <h1> File Browser </h1>
          {folderData + ','}
         </>
           <CustomModal
            showModal={isCreateFolderOpen}
            setShowModal={setIsCreateFolderOpen}
            modalHeading="Create Folder"
            modalContent={renderForm()}
          />
        </FileBrowserContext.Provider>
       )
    }

我正在 utils.tsx 上调用我的 useFileBrowserContext()。我需要上面组件中的 folderData,我打算在其中使用上下文调用该组件,以便能够将文件夹保存在我正在使用的 Chonky 库中。

export const useFileActionHandler = (
  setCurrentFolderId: (folderId: string) => void,
  createFolder: (folderName: string) => void,
) => {

  const [isCreateFolderOpen, setIsCreateFolderOpen] = useState<boolean>(false);
  const { folderData } = useFileBrowserContext();


  const handleFileCallback = useCallback(
    (data: ChonkyFileActionData) => {
      if (data.id === ChonkyActions.CreateFolder.id) {
        // CONTEXT BEING CALLED HERE
        setIsCreateFolderOpen(true);
        if (folderData) createFolder(folderData);

      } 

      console.log('file browser', folderData);
    },
    [
      createFolder,
    ],
  );

  return {
    handleFileCallback,
    isCreateFolderOpen,
    setIsCreateFolderOpen,
  };
};

我的控制台中没有错误,但行为是当我在 utils.tsx 中控制台记录 folderData 时,它返回一个空字符串,我认为这意味着从组件传递的 folderData 不起作用。提前感谢您的帮助。

【问题讨论】:

    标签: javascript reactjs typescript react-context


    【解决方案1】:

    为了让组件使用useContext,它们必须是Context.Providerdescendent。在您的情况下,您尝试在您的FileBrowser 组件中使用您的FileBrowserContext,但它不是Context.Provider 的后代,因此它接收folderData 的默认值(空字符串)。

    所以,目前你有:

    <App>
      <FileBrowser>
        <FileBrowserContext.Provider>
          {/* ... */}
        </FileBrowserContext.Provider>
      </FileBrowser>
    </App>
    

    但你需要

    <App>
      <FileBrowserContext.Provider>
        <FileBrowser>
          {/* ... */}
        </FileBrowser>
      </FileBrowserContext.Provider>
    </App>
    

    解决方法是将您的Context.Provider 组件上移一层并将其渲染为FileBrowser 的父级,而不是让FileBrowser 自己渲染它。您可以将其包装到一个自定义组件中,该组件处理设置正确的value,如下所示:

    const FileBrowserContextProvider = () => {
      const [folderData, setFolderData] = useState('');
    
      return (
        <FileBrowserContext.Provider value={{ folderData, setFolderData }}>
          {children}
        </FileBrowserContext.Provider>
      );
    };
    
    const App = () => {
      return (
        <FileBrowserContextProvider>
          <FileBrowser /> {/* <-- now FileBrowser can safely useContext
                                  since it's a descendent of the Provider */}
        </FileBrowserContextProvider>
      );
    };
    

    【讨论】:

    • 非常感谢您让我理解这一点,它解决了我的问题,现在我知道为什么它不能更早地工作了。
    猜你喜欢
    • 2022-11-29
    • 1970-01-01
    • 2020-09-19
    • 2019-11-19
    • 1970-01-01
    • 2021-09-24
    • 2021-12-24
    • 1970-01-01
    • 2023-01-18
    相关资源
    最近更新 更多