reactjs - 使用它来存储 JSX 组件以在其他地方显示是否是滥用上下文?
问题描述
我有一个应用程序,用户将在其中单击应用程序的各个部分,这将在右侧的抽屉中显示某种配置选项。
我为此得到的解决方案是将要显示的任何内容存储在上下文中。这样抽屉只需要从上下文中检索其内容,并且需要设置内容的任何部分都可以通过上下文直接设置。
这是一个演示这个的 CodeSandbox。
关键代码片段:
const MainContent = () => {
const items = ["foo", "bar", "biz"];
const { setContent } = useContext(DrawerContentContext);
/**
* Note that in the real world, these components could exist at any level of nesting
*/
return (
<Fragment>
{items.map((v, i) => (
<Button
key={i}
onClick={() => {
setContent(<div>{v}</div>);
}}
>
{v}
</Button>
))}
</Fragment>
);
};
const MyDrawer = () => {
const classes = useStyles();
const { content } = useContext(DrawerContentContext);
return (
<Drawer
anchor="right"
open={true}
variant="persistent"
classes={{ paper: classes.drawer }}
>
draw content
<hr />
{content ? content : "empty"}
</Drawer>
);
};
export default function SimplePopover() {
const [drawContent, setDrawerContent] = React.useState(null);
return (
<div>
<DrawerContentContext.Provider
value={{
content: drawContent,
setContent: setDrawerContent
}}
>
<MainContent />
<MyDrawer />
</DrawerContentContext.Provider>
</div>
);
}
我的问题是 - 这是对上下文的适当使用,还是这种解决方案可能会遇到渲染/虚拟 dom 等问题?
有没有更整洁的方法来做到这一点?(即自定义钩子?虽然 - 请记住,一些想要进行设置的组件可能不是功能组件)。
解决方案
请注意,纯粹从技术角度将组件存储在 Context 中是可以的,因为 JSX 结构只不过是最终使用React.createElement
.
但是,您尝试实现的目标可以通过门户轻松完成,并且可以让您更好地控制在其他地方渲染的组件,然后通过上下文渲染它,因为如果您直接渲染它们而不是存储,您可以更好地控制状态和处理程序它们作为上下文中的值
将组件存储在上下文中并渲染它们的另一个缺点是它使组件的调试变得非常困难。如果组件变得复杂,您通常会发现很难确定道具的供应商是谁
import React, {
Fragment,
useContext,
useState,
useRef,
useEffect
} from "react";
import { makeStyles } from "@material-ui/core/styles";
import Button from "@material-ui/core/Button";
import { Drawer } from "@material-ui/core";
import ReactDOM from "react-dom";
const useStyles = makeStyles(theme => ({
typography: {
padding: theme.spacing(2)
},
drawer: {
width: 200
}
}));
const DrawerContentContext = React.createContext({
ref: null,
setRef: () => {}
});
const MainContent = () => {
const items = ["foo", "bar", "biz"];
const [renderValue, setRenderValue] = useState("");
const { ref } = useContext(DrawerContentContext);
return (
<Fragment>
{items.map((v, i) => (
<Button
key={i}
onClick={() => {
setRenderValue(v);
}}
>
{v}
</Button>
))}
{renderValue
? ReactDOM.createPortal(<div>{renderValue}</div>, ref.current)
: null}
</Fragment>
);
};
const MyDrawer = () => {
const classes = useStyles();
const contentRef = useRef(null);
const { setRef } = useContext(DrawerContentContext);
useEffect(() => {
setRef(contentRef);
}, []);
return (
<Drawer
anchor="right"
open={true}
variant="persistent"
classes={{ paper: classes.drawer }}
>
draw content
<hr />
<div ref={contentRef} />
</Drawer>
);
};
export default function SimplePopover() {
const [ref, setRef] = React.useState(null);
return (
<div>
<DrawerContentContext.Provider
value={{
ref,
setRef
}}
>
<MainContent />
<MyDrawer />
</DrawerContentContext.Provider>
</div>
);
}
推荐阅读
- python-3.x - 如何在 Python 3.7 中创建一个通用的 id 类
- arduino - Arduino IR 控制的光衰问题
- makefile - 是否可以将变量从子 makefile 传递到顶级 makefile?
- javascript - 物化 CSS 日期选择器无法正常工作
- amcharts - amCharts 4 - 如何在没有数据添加到图表时通过属性字段设置线条颜色
- c# - 当设置为 TestFixture 级别而不是测试级别时如何获取作者属性?
- python - 如何找到一个系列中多个组的总和?
- excel - 替换没有数组公式的 MAXIFS
- c++ - C++ [std::regex] 试图只匹配中间有空格的数字
- python-3.x - 在列表中查找列表索引的优雅方法?