-
-
Notifications
You must be signed in to change notification settings - Fork 78.9k
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
refactor: use a Map instead of an Object in dom/data #32180
Conversation
@XhmikosR I realised something in the dom/data spec https://github.com/twbs/bootstrap/blob/main/js/tests/unit/dom/data.spec.js#L30-L44 The test says 'should change data if something is already stored' but it expects the |
js/src/dom/data.js
Outdated
@@ -24,7 +24,7 @@ const mapData = (() => { | |||
id++ | |||
} | |||
|
|||
storeData[element.bsKey.id] = data | |||
storeData.set(element.bsKey.id, data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The element
can not be used directly here? 🤔
Ref: #32123 (comment)
My suggestions: alpadev#1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yep the element should be used here to the data
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm that's a bit contradictory to this response #32123 (comment) but well
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
haha yes sorry @alpadev but things can change 🤷
FYI this results in a nice size decrease (approx. 1.3-1.8% from the compressed gzip files) 🙂 https://ja2r7.app.goo.gl/5pUhLMyZD1iuZgYe9 I moved this to beta1 @Johann-S. Tests do seem to pass, although I notice a few of them are removed. |
Yes, we discussed the tests here: alpadev#1, though |
js/src/alert.js
Outdated
@@ -49,7 +49,7 @@ class Alert { | |||
this._element = element | |||
|
|||
if (this._element) { | |||
Data.setData(element, DATA_KEY, this) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW the DATA_KEY
constants are only used in one place in each of the plugins except for popover.js and tooltip.js. The minifier already inlines those, so I guess we better keep them for consistency.
LGTM 👍 since we don't allow different instance on an element 👌 |
e8e3fcc
to
a03ed54
Compare
@Johann-S My only concerns are:
All in all, I love this change; it makes the code simpler and also saves us a good amount of code. I just want to make sure we aren't missing anything and that we won't be circling around in the future 🙂 |
If it's expected to have multiple keys/instances on one element in a closer future, this might be not the ideal implementation to go with, I guess. This basically removes the circuit of mapping an So before it was like: Now it's like: Another thing to mention, is that |
Sounds like we need to rethink this. Let's keep this on hold for a few days
until we get more feedback
…On Sat, Nov 21, 2020, 19:45 alpadev ***@***.***> wrote:
If it's expected to have multiple keys/instances on one element in a
closer future, this might be not the ideal implementation to go with, I
guess.
This basically removes the circuit of mapping a UID (and an DATA_KEY),
that both been stored in an object at the elements' bsKey, to an instance
that is saved in the mapData, and instead uses the 1:1 relationship of
element and instance directly with the element being the key to the
mapDatas' instance.
So before it was like:
A PluginInstance <> mapData.id <> element.bsKey.id mapping, with the
DATA_KEY only being some kind of validation to check if Data.getData or
Data.removeData is called with the same DATA_KEY that has been stored in
element.bsKey when Data.setData was called (the first time).
Now it's like:
A PluginInstance <> mapData.element <> element mapping, with the DATA_KEY
not being used here at all.
Another thing to mention, is that Plugin.getInstance(element) isn't
"type-safe" anymore. Before if I had a Tooltip bound to an element,
Tooltip.getInstance(element) would return some Tooltip-Instance, while
Button.getInstance(element) returned null. Now every Plugin.getInstance
returns whatever is saved in mapData for that element or null.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#32180 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AACVLNNCPAEPZ42CF2D3JXDSQ74C7ANCNFSM4TZA7NYQ>
.
|
If I was to propose some implementation for the data, it should look something like this: const elementMap = new Map(); // or WeakMap() even.. tbh lacking experience with WeakMaps
export default {
set(element, key, instance) {
if (!elementMap.has(element)) {
elementMap.set(element, new Map());
}
const instanceMap = elementMap.get(element);
// make it clear we only want one instance per element
// can be removed at a later time when multiple key/instances are allowed
if (!instanceMap.has(key) && instanceMap.size !== 0) {
throw new Error(
"Sorry, we currently allow only one instance per element."
);
}
instanceMap.set(key, instance);
},
get(element, key) {
if (elementMap.has(element)) {
return elementMap.get(element).get(key) || null;
}
return null;
},
remove(element, key) {
if (elementMap.has(element)) {
const instanceMap = elementMap.get(element);
instanceMap.delete(key);
// free up element references if there are no instances left for an element
// I guess this wouldn't be necessary with a WeakMap
if (instanceMap.size === 0) {
elementMap.delete(element);
}
}
}
}; This uses both an |
@alpadev yup, that sounds like a better approach since that seems closer to what we have right now :) |
@alpadev said :
The old behavior should be kept here, it's important to be type safe. And I like your other implementation (#32180 (comment)) BTW when I created |
So, assuming we follow @alpadev's suggestion, would this still be considered a breaking change? If so, we need to get this done in beta1, otherwise we can move it to beta2. |
It is not a breaking change then IMO 🤔 |
b98dcf4
to
67567f5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are some last comments to address
I didn't mean to enforce my opinion here 🙂. My intention was just to explain my standpoint and to receive some input. As I see it we have those options: Allow the use of multiple components per element
Disallow the use of multiple components
Yeah sorry.. I got my chance to try that thing called Covid and been totally mashed potato in my head for the last week or so. I'm on it. |
as mentioned by rohit2sharma95 - twbs#32180 (comment)
as requested by Johann-S - twbs#32180 (comment)
as clarified with rohit2sharma95 - twbs#32180 (comment)
as mentioned by rohit2sharma95 - twbs#32180 (comment)
Fixes #32123
Preview: https://deploy-preview-32180--twbs-bootstrap.netlify.app/