繁体   English   中英

如何正确使用带有 Typescript 的 React Context Provider?

[英]How to properly use React Context Provider with Typescript?

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

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

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 不起作用。 提前感谢您的帮助。

为了让组件使用useContext ,它们必须是Context.Provider后代 在您的情况下,您尝试在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>
  );
};

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM