我知道这个问题以前曾被问过,但通常的答案给我带来了另一个(潜在的)问题和疑问。
我有一个函数,它根据两个参数
paramA
和 paramB
返回必须渲染的组件。现在的代码看起来像这样:
if (paramA === paramATypes.PRE) {
if (paramB === paramBTypes.REQUEST) {
detailedView = (
<ComponentA
requestDetails={requestDetails as RequestDetailsDto<ComponentADto>}
/>
);
} else if (paramB === paramBTypes.MODIFICATION) {
detailedView = (
<ComponentB
requestDetails={
requestDetails as RequestDetailsDto<ComponentBDto>
}
/>
);
}
} else if (paramA === paramATypes.PRI) {
if (paramB === paramBTypes.REQUEST) {
detailedView = (
<ComponentC
requestDetails={requestDetails as RequestDetailsDto<ComponentCDto>}
/>
);
} else if (paramB === paramBTypes.MODIFICATION) {
detailedView = (
<ComponentD
requestDetails={
requestDetails as RequestDetailsDto<ComponentDDto>
}
/>
);
}
} else if...
这种情况一直持续下去,因为我们每种类型都有一些不同的类型,并且每种类型都有一个特定的组件,以某种方式呈现其属性。当然,这有点过于简单化了,只是为了能够描述情况。
问题是,我可以尝试做这样的事情,就像我通常使用更简单的值一样:
const dict = {
[paramATypes.PRE]: {
[paramBTypes.REQUEST]: <ComponentA
requestDetails={requestDetails as RequestDetailsDto<ComponentADto>}
/>,
[paramBTypes.MODIFICATION]: <ComponentB
requestDetails={
requestDetails as RequestDetailsDto<ComponentBDto>
}
/>,
},
...
}
然后就这样称呼它:
const view = dict[paramA][paramB];
我看到的问题是,使用“if-hell”时,仅当满足 if 条件时才会处理组件的值。因此,在这种情况下,每次调用只会计算/处理一个组件。
但是,如果我使用对象/字典范例,它将处理所有值,因为它需要它来创建稍后要访问的实际对象,因此每次调用此方法都会计算所有可能性,然后返回其中之一。
如果这些值只是声明或更简单的值,我不会有任何问题,但作为 React 组件我不太确定。
我对两种范式中处理它的方式是否正确?我该怎么做才能拥有更干净的条件?
也许将值定义包装在方法中,因此仅当我执行方法的结果时才会处理它,如
const view = dict[paramA][paramB]();
?
我只是想知道哪种方式是最好的表达方式,这样它不仅更容易阅读,而且还具有良好的性能(并且在代码分析器中具有良好的认知复杂性)。
谢谢!
据我所知,有两种可能的解决方案:
const dict = {
[paramATypes.PRE]: {
[paramBTypes.REQUEST]: ComponentA,
[paramBTypes.MODIFICATION]: ComponentB,
},
} as const satisfies Record<
paramATypes,
Record<paramBTypes, React.FC<{ requestDetails: RequestDetailsDto }>>
>
然后在组件中执行如下操作:
const Component = () => {
const View = dict[paramA][paramB]
return (
<div>
<View requestDetails={requestDetails} />
</div>
)
}
}
const Component = () => {
const dict = {
[paramATypes.PRE]: {
[paramBTypes.REQUEST]: () => (
<ComponentA
requestDetails={requestDetails as RequestDetailsDto<ComponentADto>}
/>
),
[paramBTypes.MODIFICATION]: () => (
<ComponentB
requestDetails={requestDetails as RequestDetailsDto<ComponentBDto>}
/>
),
},
} as const satisfies Record<paramATypes, Record<paramBTypes, React.FC>>
const View = dict[paramA][paramB]
return (
<div>
<View />
</div>
)
}
在这两种情况下,仅渲染正确的组件,而不是所有可能的组件,因此从性能角度来看,您的表现很好
你应该尝试第一个选项,因为它使道具统一并使一切更易于维护,
只是发人深省,因为它不太常用,但确实避免了 if-else 以及字典(其他解决方案仍然使用字典):您可以将
if-else
编码到数据结构中并制作它几乎看不见:
/* This is the data structure that "stands in" for if-conditionals */
function Conditional(component, predicate) {
// A "conditional component" is an object with two fields:
// - The component, tacked into a thunk
// - A variadic predicate function
const it = Object.create(Conditional.prototype);
it.component = () => component;
it.predicate = predicate;
return it;
}
Conditional.getRenderer = (...conditionals) => (...params) => {
// Takes N conditional components and returns a renderer function that awaits data
return conditionals.reduce(
(result, conditional) => result == null ? conditional.render(...params) : result,
null
);
};
Conditional.prototype.render = function (...params) {
// Renders a conditional component if the associated predicate accepts the data
return this.predicate(...params) ? this.component() : null;
};
/* These are the "dummy" components */
const ComponentA = (details) => `A(${details.msg})`;
const ComponentB = (details) => `B(${details.msg})`;
const ComponentC = (details) => `C(${details.msg})`;
/* This is the 'render' function that encodes the 'if-else' branching */
const render = Conditional.getRenderer(
Conditional(ComponentA, (a, b) => a === 'a' && b < 2),
Conditional(ComponentB, (a, b) => a === 'b'),
Conditional(ComponentC, () => true)
);
/* Try it */
console.log(render('a', 0)({ msg: 'details' })); // Should be 'A(details)'
console.log(render()({ msg: 'more details' })); // Should be 'C(more details)'
console.log(render('b', 2)({ msg: 'other details' })); // Should be 'B(other details)'
请注意,涉及一种“后备”组件(ComponentC)
它有一个始终返回 true 的关联谓词。打电话时该组件必须是最后输入的!getRenderer