簡體   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