我目前正在做一个需要动态地将一个组件注入另一个组件的项目。
我的项目使用Redux,所以我想出了两种可能的解决方案,都有各自的优点和缺点,但我不知道该选择哪一个。我知道天性,鼓励成分发生反应,但我还是很想知道如果第二种方法(更简单和更快的使用)仍然是好:
export const SlideOverComponents = {
'UserCreate': UserCreate,
'UserUpdate': UserUpdate,
};
这个想法是将所有可以注入的组件注册为一个键值对,并使用该组件所需的键和道具调度一个Redux操作。
{(!!componentKey && !!SlideOverComponents[componentKey]) && React.createElement(SlideOverComponents[componentKey], props)}
然后在我的父容器中,我只是读取这个键并使用React。
这个解决方案工作得很好,使用起来很容易,也很快速,因为我只需要将任何新组件注册到对象中就可以使其工作。
这种方法"ok"吗?? 或者我应该使用合成吗?
(我的要求来自一个"良好的实践")或";anti-pattern"观点)
可以,只要所有SlideOverComponents
之间的接口完全相同即可。您的代码比需要的更冗长。如果你先把createElement
赋值给一个变量,你也不需要它
const Component = SlideOverComponents[componentKey]
return (
<div>
{Component && <Component {...props} />}
</div>
)
type SlideOverComponentsType = "update" | "create";
type SlideOverComponentsProps = UserUpdateProps | UserCreateProps;
type SlideOverProps = {
key: SlideOverComponentsType;
} & SlideOverComponentsProps;
function SlideOver({ key, ...props }: SlideOverProps) {
switch (key) {
case "update":
return <UserUpdate {...props} />;
case "create":
return <UserCreate {...props} />;
default:
return null; // this will never happen but need to be addressed
}
}
使用这样的方法,您不需要"Object"来存储所有可能类型的SlideOverComponents
。你也总是会保证道具使用适当的接口,如果最终,你通过它错误的TS会警告你。
再次说明:考虑使用类型而不是声明"options"在这种情况下作为对象。
希望这能帮助你或给你一些好主意!
原始答:
你仍然可以使用Composition,并在"Generic"组件中创建某种检查或"switch"语句。这样,你就可以避免在父组件之外添加那么多的检查(if’s),并保证最终不存在的"键"可以退回到默认行为,甚至是错误。有几种实现它的方法,但我喜欢使用switch
的一种方法是:
function UserInteraction({ key, ...props }) {
switch (key) {
case "create": {
return <UserCreate {...props} />;
}
case "update": {
return <UserUpdate {...props} />;
}
default: {
return null;
// or you could thrown an error with something like
throw new Error(`Error: key ${key} not present inside component User`);
}
}
}
您也可以使用Object.keys()
方法来完成几乎相同的行为:
const UserInteractionOptions = {
"create": UserCreate,
"update": UserUpdate,
}
function UserInteraction({ key, ...props }) {
if (!Object.keys(UserInteractionOptions).includes(key)) {
return null;
// or you could thrown an error with something like
throw new Error(`Error: key ${key} not present inside component User`);
}
const InteractionComponent = UserInteractionOptions[key];
return <InteractionComponent {...props} />;
}
主要思想是将逻辑与决定在该组件中呈现哪个组件(以及是否可以呈现)隔离开来。
为了以后的阅读,你可以检查TypeScript以及如何通过类型、强制转换和检查不存在的keys
,甚至可以在代码在本地运行之前进行检查来轻松地处理这个问题。
有点挑剔:你不是在"注射";一个组件内部的另一个组件。你只是通过一个标志传递一个key
来决定父组件是否渲染子组件。将一个组件注入到另一个组件中需要将整个组件作为道具传递,然后渲染它(或者最终自定义它)。您可以查看React如何决定渲染children
道具,以及它如何决定是null
、string
还是ReactComponent
来渲染实际组件。此外,一个很好的研究主题是依赖注入。
作为一个简单的例子,注入一个组件可以像这样:
function Label({ text }) {
return <p>{text}</p>;
}
function Input({ Label, ...props }) {
return (
<div>
<Label />
<input {...props} />
</div>
);
}