-
Notifications
You must be signed in to change notification settings - Fork 29
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
A fractal-component implementation which respects the open/closed principle #46
base: master
Are you sure you want to change the base?
Conversation
Hi @ghola, 1> Regarding the
Having said that, either 2> While looking into your issue, I discovered a compatible issue with You probably won't be impacted by this issue as 3> You don't need to rely on
A 4>
It seems 5>
I like the two scenarios you described here. It does provide more useful sample cases for more discussion around this area 😄 Regarding your solution, it seems it move some logic out to App level. I think we probably look for a solution of encapsulating logic into components. You can argue that having a To be honest, I think for component encapsulation, most important thing is to try making no assumption of outside world. It's probably OK that an encapsulated component can't meet everyone's need (or any changes) as it's supposed to be reused for a certain purpose. If a user finds a component can't meet his requirement, he probably can ask the component author to update the component to accomodate the new logic. Having said that, I am still quite interested in the two scenarios you've described above. Are you able to demostrate a solution that:
P.S. If possible, could you please create your PR to a different directory? e.g. |
Hey @t83714, thank you for the hints on the errors I encountered. Not using TypeScript sure makes one's life harder. 3> I understand how actions get published down the namespace tree (it's an entire discussion whether this is a harmful or a beneficial limitation). I also agree with Given the way One alternative would be just throwing it in the global namespace, but I think that should be avoided as well. Thinking in terms of RabbitMQ topics for a bit here, you can publish messages on a distinct topic/exchange and only interested parties will subscribe and receive them. Throwing them in the global topic is just pollution, especially when you might have difficulties distinguishing between message types (I know Symbol ensures uniqueness, but when you look in your redux dev tools at the actions, you'll still be confused). In the end, that's why I suggested that a component should be able to subscribe to messages from a different namespace without resorting to using the ActionForwarder. 5>
Imagine you have a chat application which is composed of a left side panel which lists the users and a right panel which displays the conversation with the currently selected user (very similar to Whatsapp for desktop). When you receive a new message for a user which is not the one you're currently chatting with, you need to display the number of unread messages next to the user's icon. Let's also assume that it's the right panel doing the checking/loading of all the messages and can display the current conversation for the user being passed via props. The right panel component needs to notify the left side panel of the messages as they arrive, so the side panel can display those bubbles next to the user's icon. Also, it needs to notify the side panel when the messages get read (maybe there are many messages and they get read as the right panel gets scrolled). These two can be pretty independent components, siblings at application level, but they need to communicate. In this contrived example the communication is one way, but it could be two way as well. You'd still need some glue code and some state at application level, but doing that would not produce a flat structure app. The two components representing the left and side panel would not be dumb at all, but they need to publish events to the outside world so others get a chance to react to them. It doesn't mean you lose encapsulation. It's like publishing events at the border of a domain context in DDD. I cannot demonstrate a solution that encapsulates ALL logic into components. The "App" component is a forced one and is only there because it reduces friction with the framework ( I will make the PR to a different directory as you asked. |
04695fb
to
89576e9
Compare
@t83714 Made it fully functional and made the push to the |
@t83714 On more thing regarding raising the state up to App level. That's not really necessary. The business logic here is only concerned with how the Counter component performs. This means we could make a CounterWrapper HOC which does all that forwarding/listening to events from other components. Whether such a component would be publishable as an NPM module, is debatable. I would say it's not because it's implementing very specific business rules. This argument is just to counter the uneasiness you may have from having the state lifted all the way up to App level, if any. |
Hi @ghola,
<div>
<div className={classes.table}>
<div className={classes.cell}>
<RandomGif namespacePrefix={this.componentManager.fullPath} />
</div>
<div className={classes.cell}>
<Counter namespacePrefix={this.componentManager.fullPath} />
</div>
</div>
<div className={classes.table}>
<div className={classes.cell}>
<RandomGifPair namespacePrefix={this.componentManager.fullPath} />
</div>
<div className={classes.cell}>
<ToggleButton namespacePrefix={this.componentManager.fullPath} />
</div>
</div>
<div>
<RandomGifPairPair namespacePrefix={this.componentManager.fullPath} />
</div>
</div> You will also want to dispatch
2> By looking at your code, the counter component saga looks like doesn't play too much role as main logic has been moved to 3> I am very interested in the Cheers~ |
Changes to the
fractal-lcomponent
implementation so it respects the open/closed principle. More details about them are present in #45.@t83714 It's not functional, but you can clearly see the intent. I have encountered several issues:
ActionForwarders
, but aside from publishing the actions in the global namespace, there seems to be no way a component can listen to them if they are not forwarded. Maybe some of the forwarder functionality built into the component would help (something like theallowedIncomingMulticastActionTypes
array which would allow you also specify the namespace you want to listen to).randomGifActionTypes.TOGGLED_ON
which gets dispatched once by theToggleButton
component, and then an additional 2 times by the forwarder (when it should be just once by the forwarder).randomGifActionTypes.NEW_GIF
actions withrelativeDispatchPath="../App/*"
results in an error:Anyway, you can fix it if you think it's worth it. My goal was only to exemplify the ideas discussed in #45, so I will not continue developing this example.
I was mentioning a change in business rules so we can see how solutions adapt to that. Here are some possible rule changes:
Assume that your components are published as NPM modules. In your implementation you need to make changes to them in order to implement the above business rules. In my implementation you don't, you only need to make changes to the App component which is not published to NPM.