我有一个React应用程序,它使用方法getInitialInfo
异步获取其信息。 MessageView
是最重要的组成部分,因此,数据应该处于其状态,即使它不会改变。在一个完美的世界中,IMessageInfo
将通过道具。
我们需要export
类型IMessageInfo
,因为有代码依赖于这个接口。
方案1 - (没有私人国家的扁平解决方案)
import * as React from 'react';
import Message from './Message';
// IMessageInfo needs to be exported because there is code that depends on it
export interface IMessageInfo {
message: string;
icon: string;
}
export interface IMessageViewProps {
getInitialInfo(): Promise<IMessageInfo>;
}
// MessagesView is the upper most Component
class MessageView extends React.Component<IMessageViewProps, IMessageInfo> {
constructor(props) {
super(props);
this.state = {
message: '',
icon: ''
};
this.getInitialInfo();
}
private async getInitialInfo(): void{
let info = await this.props.getInitialInfo();
this.setState(info);
}
render(): JSX.Element {
// Message is reusable component that receives the info through `props`
return <Message {...this.state} />);
}
}
从React的设计角度来看,State
必须是组件的私有。我同意这一点。但在这里,所有州的信息都是公开的。什么可以抛出这种概念方式。 (例如,如果DATA总是在演示者中管理,为什么在这种情况下它应该是私有的?)
选项2 - (平面解决方案,具有State的私有复制接口)
与一些同事交谈时,他们认为我们应该始终将国家保密。我立即考虑创建一个与IMessageViewState
完全相同的IMessageInfo
。这样,它在概念上是正确的,但我们会得到一个维护问题(IMessageInfo
和IMessageViewState
在其某些成员更改时更新)。
选项3 - (将IMessageInfo编写为IMessageViewState。具有私有状态)
因此,我的同事建议将IMessageViewState
定义为:
interface IMessageViewState {
messageInfo: IMessageInfo;
}
这样我们就喜欢构图(他们说)。但我认为这里没有任何优势。你看到了吗?例如,如果IMessageInfo
的任何成员发生更改(消息或图标),我们需要将所有对象messageInfo
传递给this.setState(...)
,而不是仅更新icon
。基本上,这将是一个更容易出错的实现。
选项4 - (扩展IMessageInfo。具有私有状态)
我还想过让IMessageViewState
扩展IMessageInfo
。这似乎是完成未导出状态的最佳解决方案。但是我的同事说这不是一个好的解决方案,因为我们优先考虑组合。
我认为继承不会带来任何回归。
结论
在我看来,选项1是最适合问题的选项。由于国家所有成员都是公开的,我认为没有必要建立一个私人国家。选项1使代码更清晰。
虽然,如果我选择一个私有州的解决方案,选项4将更适合。
问题:哪种解决方案更正确?
我认为这是对interface
和state
的一些误解。接口只是某个对象的类型。因此,您可能拥有单独的文件,可以为您解决所有必需的接口。 IMessageInfo
可能会在几个地方使用。
State
是某种类型的对象。它可以是IMessageInfo
或其他类型。 state
是一个组件的私有。这是React的design。
您可以考虑使用Redux的其他选项,使state
成为整个解决方案的核心。在这种情况下,IMessageInfo
可以从负责MessageInfo的部分商店导出。
例
// store/MessageInfo.cs
export interface IMessageInfo { /*...*/ }
const initalMessageInfo: IMessageInfo = { /*...*/ }
export const actionCreators = {
requestMessageInfo () //...
}
export const reducer: Reducer<IMessageInfo> //...
在这种情况下,你将(1)通过你的解决方案保持IMessageView
sigle,(2)根据你的解决方案的几个组件可用的state
制作IMessageInfo
。
这样我们就喜欢构图(他们说)。但我认为这里没有任何优势。你看到了吗?例如,如果IMessageInfo的任何成员发生更改(消息或图标),我们需要将所有对象messageInfo传递给this.setState(...),
考虑需要向MessageView
内部状态添加更多数据的情况。选项3针对以下情况进行了优化:
interface IMessageViewState {
messageInfo: IMessageInfo;
}
当它从一开始就以这种方式分离时,很明显你可以在哪里添加你需要添加到私有状态的数据:它被添加到非导出的IMessageViewState
,而不会影响导出的IMessageInfo
接口的任何用户。
如果你100%确定IMessageInfo
拥有MessageView
课程所需的一切,你可以选择1。