React - Composition VS Configuration



我目前正在做一个需要动态地将一个组件注入另一个组件的项目。

我的项目使用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>
)
编辑:我注意到你正在使用其他答案中的TypeScript。考虑到这一点,我仍然认为你可以使用组合,但类型使用字符串文字类型,像这样:
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道具,以及它如何决定是nullstring还是ReactComponent来渲染实际组件。此外,一个很好的研究主题是依赖注入。

作为一个简单的例子,注入一个组件可以像这样:

function Label({ text }) {
return <p>{text}</p>;
}
function Input({ Label, ...props }) {
return (
<div>
<Label />
<input {...props} />
</div>
);
}

最新更新