如何解决React Context API 不适用于单个应用程序对话框
我想创建一个对话框组件来渲染一次并在整个应用程序中使用它,而不是每次需要显示一个对话框时都创建一个对话框组件。
Context API 最初正确显示对话框。如果对话框仅包含静态文本,则显示正确。但是如果对话框包含任何动态元素,它不会对更改做出反应。
我使用自定义钩子处理对话框。
这是一个带有静态文本的对话框示例:
export function useStaticTextDialog(callback) {
const appContext = useContext(AppContext);
const openDialog = () => appContext.openAppDialog(appDialogContext);
const onDialogOk = () => {
appContext.closeAppDialog(); // close unique app dialog first in case the callback uses it
callback();
};
const appDialogContext = {
title: 'Static text',content: 'This static text works.',onOk: onDialogOk,onClose: appContext.closeAppDialog,};
return { open: openDialog };
}
它的名字是这样的:
const staticTextDialog = useStaticTextDialog(callback);
staticTextDialog.open();
单个组件在应用组件中渲染一次:
import AppDialog from 'components/appDialog';
function App() {
return (
<AppContextProvider>
<Router />
<AppDialog />
</AppContextProvider>
);
}
上下文非常简单:
import React,{ createContext,useState } from 'react';
const AppContext = createContext();
function AppContextProvider({ children }) {
const [isAppDialogOpen,setIsAppDialogOpen] = useState(false);
const [appDialogContext,setAppDialogContext] = useState({});
const openAppDialog = appDialogContext => {
setAppDialogContext(appDialogContext);
setIsAppDialogOpen(true);
};
const closeAppDialog = () => setIsAppDialogOpen(false);
const appContextValue = {
isAppDialogOpen,appDialogContext,openAppDialog,closeAppDialog,};
return <AppContext.Provider value={appContextValue}>{children}</AppContext.Provider>;
}
export { AppContext,AppContextProvider };
嗯,到目前为止是有效的。但是如果将动态元素添加到对话框中,它不会对更改做出反应并显示过时的值:
export function useDynamicTextDialog(callback) {
const appContext = useContext(AppContext);
const [name,setName] = useState();
const openDialog = newName => {
setName(newName);
appContext.openAppDialog(appDialogContext);
};
const onDialogOk = () => {
appContext.closeAppDialog(); // close unique app dialog first in case the callback uses it
callback(name);
};
const appDialogContext = {
title: 'Overwrite warning',content: `The name "${name}" already exists. Are you sure you want to overwrite it?`,};
return { open: openDialog };
}
如果对话框包含表单元素(如文本框或下拉列表),则该对话框也不起作用。它不会对用户的新值做出反应。
我发现这种行为出乎意料,我认为它应该对更改做出反应并正常工作。 当渲染多个对话框组件时,这种方式实际上也有效,每次需要一个对话框时一个。在这种情况下不使用上下文 API。示例:
import DialogTemplate from 'components/dialogTemplate';
export function useDynamicTextDialog(callback) {
const [isDialogOpen,setIsDialogOpen] = useState(false);
const [name,setName] = useState();
const openDialog = newName => {
setName(newName);
setIsDialogOpen(true);
};
const closeDialog = () => setIsDialogOpen(false);
const onDialogOk = () => {
closeDialog ();
callback(name);
};
const dialogContext = {
title: 'Overwrite warning',onClose: closeDialog,};
const Dialog = <DialogTemplate dialogContext={dialogContext} />;
return { Dialog,open: openDialog };
}
然后它会在某处打开,就像单个应用程序对话框一样:
const dynamicTextDialog = useDynamicTextDialog(callback);
dynamicTextDialog.open();
但在这种情况下必须呈现每个对话框组件:
function Component() {
const { dynamicTextDialog } = useDynamicTextDialog();
return (
<div>
{...more elements}
{applicationClosingWarningDialog.Dialog}
</div>
);
}
因此,如果使用 20 个对话框,则必须渲染 20 个对话框组件,尽管除了内容之外它们几乎相同。
这就是为什么我想为整个应用程序只使用一个对话框组件,每次都重复使用它并且只更改内容。但是 Context API 不起作用。
为什么它适用于带有对话框模板的示例,而不适用于带有上下文的应用程序对话框的示例,即使数据的处理方式相同?
如何让它与 Context API 一起工作?
解决方法
Context API 不会对对话框的更改做出反应,即使它的使用方式与工作的模板组件相同。
因此,必须在对话框更改时专门触发渲染:
useEffect(() => {
appContext.setAppDialogContext(dialogContext);
},[name]);
完整的钩子:
export function useDynamicTextDialog(callback) {
const appContext = useContext(AppContext);
const [name,setName] = useState();
useEffect(() => {
appContext.setAppDialogContext(dialogContext);
},[name]);
const openDialog = newName => {
setName(newName);
appContext.openAppDialog(appDialogContext);
};
const onDialogOk = () => {
appContext.closeAppDialog(); // close unique app dialog first in case the callback uses it
callback(name);
};
const appDialogContext = {
title: 'Overwrite warning',content: `The name "${name}" already exists. Are you sure you want to overwrite it?`,onOk: onDialogOk,onClose: appContext.closeAppDialog,};
return { open: openDialog };
}
带有模板的对话框和单个对话框应用程序的演示:
https://ams777.github.io/react-single-app-dialog
演示代码:
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。