嗨,伙计们(我可能有一个奇怪的问题,但我处于死胡同。
我有自己的定制钩子。
const useModal = (Content?: ReactNode, options?: ModalOptions) => {
const { isOpen, close: contextClose, open: contextOpen, setContent } = useContext(
ModalContext,
)
const [customOpenContent, setCustomOpenContent] = useState<ReactNode>()
const showModal = useCallback(
(customContent?: ReactNode) => {
if (!isNil(customContent)) {
setCustomOpenContent(customContent)
contextOpen(customContent, options)
} else contextOpen(Content, options)
},
[contextOpen, Content, options],
)
const hideModal = useCallback(() => {
contextClose()
}, [contextClose])
return { isOpen, close: hideModal, open: showModal, setContent }
}
这很简单。 我也有使用此钩子的组件
const App: React.FC = () => {
const [loading, setLoading] = useState(false)
const { open } = useModal(null, { deps: [loading] })
useEffect(() => {
setTimeout(() => {
setLoading(true)
}, 10000)
})
const buttonCallback = useCallback(() => {
open(<Button disabled={!loading}>Loading: {loading.toString()}</Button>)
}, [loading, open])
return (
<Page title="App">
<Button onClick={buttonCallback}>Open Modal</Button>
</Page>
)
}
主要问题是 - 按钮没有启用,因为 useModal 钩子对更改一无所知。
您可能知道如何在更新道具时更新此组件?以及如何帅气地做到这一点((
上下文不是解决此问题的最佳方法。你想要的是一个门户。门户是 React 在当前 React 组件层次结构之外渲染的解决方案。如何使用 React Portal?是一个基本示例,但如您所见,仅使用基本React.Portal
只会为您提供要渲染的位置。
这里有一个图书馆,可以为你做很多繁重的工作:https://github.com/wellyshen/react-cool-portal。它具有打字稿定义,并提供了易于使用的API。
这是您使用 react-cool-portal 的示例。
import usePortal from "react-cool-portal";
const App = () => {
const [loading, setLoading] = useState(false);
const { Portal, isShow, toggle } = usePortal({ defaultShow: false });
useEffect(() => {
setTimeout(() => {
setLoading(true);
}, 10000);
});
const buttonCallback = useCallback(() => {
toggle();
}, [toggle]);
return (
<div title="App" style={{ backgroundColor: "hotpink" }}>
<button onClick={buttonCallback}>
{isShow ? "Close" : "Open"} Modal
</button>
<Portal>
<button disabled={!loading}>Loading: {loading.toString()}</button>
</Portal>
<div>{loading.toString()}</div>
</div>
);
};
基本代码沙盒示例
在 react-cool-portal 文档中有更详细的内容。
有关您正在尝试的上下文解决方案问题的更多详细信息,React Elements 只是一个 javascript 对象。然后 React 使用对象,它在树中的位置,确定它们是否是同一元素是关键。React 实际上并不关心或注意到你在哪里创建对象,只关心它在渲染时在树中的位置。
解决方案中的断开连接是,当您将元素传递给buttonCallback
中的open
函数时,将在该点创建元素。它是一个 javascript 对象,然后设置为上下文中的内容。此时,对象已设置,在您再次调用open
之前不会更改。如果将组件设置为每次相关状态更改时调用open
,则可以使其以这种方式工作。但正如我之前提到的,上下文不是为在当前组件之外呈现组件而构建的;因此,为什么需要一些非常奇怪的解决方法才能使其工作。