javascript - 如何正确使用带有 Typescript 的 React Context Provider?
问题描述
我已经持续了好几个小时试图寻找我认为可行但无法做到的东西。你能帮我解决这个问题吗?
我在这里有我的文件浏览器上下文,我想在其中传递 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 不起作用。提前感谢您的帮助。
解决方案
为了使用组件useContext
,它们必须是a的后代Context.Provider
。在您的情况下,您尝试FileBrowserContext
在FileBrowser
组件中使用您的,但它不是 a 的后代,因此它接收(空字符串)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>
);
};
推荐阅读
- python - 两个字典列表的数据操作
- swift - 程序化导航控制器不可见?
- ruby-on-rails - 如何更改附加图像的属性
- sql - 如果 .sql 文件中的第一行是注释,则 VBA ADOBD.Recordset 将不会打开
- performance - 光线调谐;将基于人群的培训计划与 Hyperopt 相结合
- regex - 使用 REGEX 删除最后的前导零
- git - 无法将 refs 推送到远程尝试先运行 pull 以集成您的更改
- asp.net-mvc - 应该存储哪些 JWT 令牌以供以后使用?
- powershell - PowerShell (Get-Content -Path "Config.txt" -TotalCount ($aVariable + 2)[-1]) 得到 2 行而不是 1 行
- node.js - 使用 Sequelize 获取 360 万条记录会导致 Node 崩溃,MariaDB 连接器可以正常工作。知道为什么吗?