I have a React App that gets asynchronously its info with the method getInitialInfo
. The MessageView
is the uppermost component, so, the Data should live in its state, even if it will not change. In a perfect world, the IMessageInfo
would be passed through props.
We need to export
the type IMessageInfo
because there is code that depends on this interface.
OPTION 1 - (Flat solution with no private State)
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} />);
}
}
From the React's design perspective the State
must be private to the component. I agree with that. But here, all the state info is Public. what can throw this concept way. (If the DATA is always managed in a presenter for example, why should it be private in this case?)
OPTION 2 - (Flat solution, having a private replicated interface for State)
Talking with some colleagues, they argue that we should always keep the state private. I immediately thought about creating a IMessageViewState
that would be exactly the same as IMessageInfo
. This way, it gets conceptually right but we would get a maintenance issue (IMessageInfo
and IMessageViewState
to update whenever some of its members change).
OPTION 3 - (Compose IMessageInfo into IMessageViewState. Has a private state)
So, my colleagues suggested to define IMessageViewState
as:
interface IMessageViewState {
messageInfo: IMessageInfo;
}
This way we are favoring composition (they say). But I don't see any advantage to have composition here. Do you see any? For example, if any member of the IMessageInfo
changes (message or icon), we would need to pass all the object messageInfo
to the this.setState(...)
, instead of only updating the icon
for example. Basically, it would be a more error-prone implementation.
OPTION 4 - (Extend IMessageInfo. Has a private state)
I also thought about having IMessageViewState
extending IMessageInfo
. It seems the best solution to accomplish a state that is not exported. But my colleagues said that it's not a good solution because we are giving priority inheritance over composition.
I think that inheritance doesn't bring any throwback in here.
CONCLUSION
In my opinion, the Option 1 is the one that best fits the problem. Since all members of the State are public, I think there's no need to have a private State. The Option 1 keeps the code cleaner.
Although, if I were to choose a solution with a private State, the Option 4 would fit better.
QUESTION: What solution would be more correct?