Conversation
Codecov Report
@@ Coverage Diff @@
## master #410 +/- ##
==========================================
- Coverage 91.79% 90.41% -1.39%
==========================================
Files 41 41
Lines 1329 1356 +27
Branches 193 198 +5
==========================================
+ Hits 1220 1226 +6
- Misses 105 126 +21
Partials 4 4
Continue to review full report at Codecov.
|
| // ------------------------------------ | ||
|
|
||
| _find = (target, autoCreate = true) => { | ||
| private _find = (target, autoCreate = true) => { |
There was a problem hiding this comment.
can we add also typings for methods' parameters, in regards to refactoring of event stack?
There was a problem hiding this comment.
btw, you might consider it as separate PR
There was a problem hiding this comment.
would rather focus on functionality in this PR - those haven't existed before, would like to devote PR to introduce them
There was a problem hiding this comment.
@kuzhelov - I think whenever we claim we'll add something in a follow-up PR we should create tickets or issues to actually track the work so that it won't slip through the cracks and other devs have access to it and can pick it up
src/components/Popup/Popup.tsx
Outdated
|
|
||
| private closeAndFocusTriggerOnClickIfOpen() { | ||
| if (this.state.open) { | ||
| setTimeout(() => this.clickSubscription.replaceWith('click', this.closeAndFocusTrigger)) |
There was a problem hiding this comment.
in your previous refactoring setTimeout was part of EventStack and, as I understood, a motivation of it was performance reason (please, correct me, if I am wrong). So the question is, should we leave it as part of the library so everyone who uses it can benefit from it? It can be as a separate method subscribeAsync.
There was a problem hiding this comment.
this is a very good point. Actually, for now have decided to move this aspect to the client's code, as have discovered few additional subtle problems that may arise with eventStack's logic (and the fact that subscription handler could be called at the same JS frame).
The simplest example - suppose that there is a following client code:
foo() {
// note, with 'setTimeout' this subscription will be made async
const subscription = EventStack.subscribe('click', ...)
// so there is, in fact, no active subscription at this point
subscription.unsubscribe()
}Note that if subscription logic is async, this will result in subscription still being active at the end of the method - as 'unsubscribe' will be invoked at the moment when there is no subscription made yet.
One simplest solution would be to make all the necessary methods async, but this will complicate client's code. What I am thinking about, however, is a bit more elaborative approach where all these bits will be handled properly by eventStack, at the same time without switch to async model requested from the client (as async methods are quite error and race condition prone to be used in React event handlers). Now am working on the PR where would like to address this problem.
src/components/Popup/Popup.tsx
Outdated
|
|
||
| private static isBrowserContext = isBrowser() | ||
|
|
||
| private clickSubscription = EventStackSubscription.empty() |
There was a problem hiding this comment.
It may be a good idea to add a prop to choose if the popup should be closed onClick. We may want to have it true by default
There was a problem hiding this comment.
just as a counterargument, we might argue that as long as Popup supports controlled mode, there are all the necessary tools to customize Popup's behavior.
Please, don't get me wrong - personally, see this suggestion as being absolutely reasonable. At the same time, would like to keep this PR simple and targeted to specific thing that it is aimed to address, so that we would be able to decide on this proposed prop later and, if necessary, introduce separate PR for that.
| const { forceFocusInsideTrap, isClickableOutsideFocusTrap } = this.props | ||
| if (forceFocusInsideTrap) { | ||
| eventStack.sub('focus', this._handleOutsideFocus, { | ||
| this._focusSubscription.unsubscribe() |
There was a problem hiding this comment.
What is the main point to call unsubscribe before actual subscription? Can't we assure that we are unsubscribed from any events at the initialization EventStack.noSubscription?
There was a problem hiding this comment.
+100 it doesn't look like a good pattern, we don't want to attempt teaching developers to do this, they will forget; I find the eventStack util difficult to use now
There was a problem hiding this comment.
please, be specific about 'do what', thanks! Because see the following as a counterargument to the statement 'hard to use now':
now
// safe subscription
const subscription = EventStack.subscribe('onclick', () => { .. /* processing logic here */ })
// - this object has IntelliSense support
// - safe unsubscribe instruction
subscription.unsubscribe() before
// ooops
eventStack.sub('onclick', () => { ... })
// ooops
eventStack.sub('onclick', this.handleClick.bind(this))
eventStack.sub('onclick', this.handleClickWithBoundThis, { useCapture: true })
// oooops
// - what were the arguments I've subscribed with?
// - some of them are critical for proper unsubscription
eventStack.unsub('onclick', this.handleClickWithBoundThis)Sorry, but now cannot agree with the point mentioned
There was a problem hiding this comment.
I agree that it looks much better now, that it was. The only my concern was about calling unsubscribe before actual subscribe, as it seems to me not very intuitive.
There was a problem hiding this comment.
The only my concern was about calling unsubscribe before actual subscribe, as it seems to me not very intuitive.
Here I would note that this is not something that is directly eventStack-related, as what we are doing is the following:
- we would like to subscribe and store subscription in the object's field
- there is (maybe) a pending subscription stored in this field - thus, we need to unsubscribe for it
- as it is safe to call 'unsubscribe' on 'noSubscription', we are not making any null checks for it. If
nullvalue will be used as initialiser, we would write something likesubscription && subscription.unsubscribe()
- as it is safe to call 'unsubscribe' on 'noSubscription', we are not making any null checks for it. If
- then we are making new subscription, storing reference on it
*Note that initially the following API was suggested for it, but we've agreed to cancel/postpone it:
// terminates previous subscription and replaces with new one
this.clickSubscription.replaceWith('click', ...)
bmdalex
left a comment
There was a problem hiding this comment.
pls take a look at comments
| const { forceFocusInsideTrap, isClickableOutsideFocusTrap } = this.props | ||
| if (forceFocusInsideTrap) { | ||
| eventStack.sub('focus', this._handleOutsideFocus, { | ||
| this._focusSubscription.unsubscribe() |
There was a problem hiding this comment.
+100 it doesn't look like a good pattern, we don't want to attempt teaching developers to do this, they will forget; I find the eventStack util difficult to use now
| // ------------------------------------ | ||
|
|
||
| _find = (target, autoCreate = true) => { | ||
| private _find = (target, autoCreate = true) => { |
There was a problem hiding this comment.
@kuzhelov - I think whenever we claim we'll add something in a follow-up PR we should create tickets or issues to actually track the work so that it won't slip through the cracks and other devs have access to it and can pick it up
mnajdova
left a comment
There was a problem hiding this comment.
I briefly took a loot into this, but seems that other developers already review it. Approving as all comments are resolved.
TODO
Close Popup on mouse click
This set of changes introduces functionality that will close
Popupon click. CurrentlyPortalis not reused, as there is some refactoring planned for this component before reusing it inPopup. At the same time, provided changes introduce full set of functionality client would expect, so this remains to be just a question of further refactoring (Portal) and generalization (reusePortal).EventStack subscription API adjustments
Event stack subscriptions were reworked, to make the API for subscribing and unsubscribing to be safer. Please, consider to take a look on the following comment for more details on that: #391 (comment)