Skip to content
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

Clarify reason for setTextContent helper #11813

Merged
merged 2 commits into from
Jan 5, 2018
Merged

Clarify reason for setTextContent helper #11813

merged 2 commits into from
Jan 5, 2018

Conversation

jquense
Copy link
Contributor

@jquense jquense commented Dec 8, 2017

Some little thing’s I noticed, referencing the code here writing some of react-dom-lite

return;
}
}
node.textContent = text;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i'm not sure this is safe, but it seems to be. We use straight sets on textContent elsewhere

@jquense
Copy link
Contributor Author

jquense commented Dec 8, 2017

also, there seems to be some duplication or extra work being done in diffProperties? I could definitely be reading it wrong, the loops there are hairy, but this loop:

for (styleName in lastStyle) {
if (lastStyle.hasOwnProperty(styleName)) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = '';

seems to be essentially duplicated lower down in the nextProp loop:

if (
lastProp.hasOwnProperty(styleName) &&
(!nextProp || !nextProp.hasOwnProperty(styleName))
) {
if (!styleUpdates) {
styleUpdates = {};
}
styleUpdates[styleName] = '';
}
}

}
} else if (typeof nextProp === 'number') {
setTextContent(domElement, '' + nextProp);
domElement.textContent = '' + nextProp;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why stringify here and not line 295?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

textContent applies stringify and sanitization AFAIK

@@ -340,7 +338,7 @@ function updateDOMProperties(
} else if (propKey === DANGEROUSLY_SET_INNER_HTML) {
setInnerHTML(domElement, propValue);
} else if (propKey === CHILDREN) {
setTextContent(domElement, propValue);
domElement.textContent = propValue;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise, should we stringify?

Copy link
Contributor Author

@jquense jquense Dec 19, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the stringify happens in diffProperties for update, so the value is already a string here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it. In any case, this looks consistent with the old behavior. 👍

Copy link
Contributor

@nhunzaker nhunzaker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems good to me, is there anything I can help to verify?

@jquense
Copy link
Contributor Author

jquense commented Dec 19, 2017

I'm not sure how to verify honestly. It's looks to me like the setTextContent was legacy considering the "modern" usages just use text Content, but perhaps someone with more perspective knows? In particular that one branch is really special, I was assuming it was for ie8 (per the comment) but I'm not sure the acceptance criteria for that

@@ -670,7 +668,7 @@ export function diffProperties(
}
for (propKey in nextProps) {
const nextProp = nextProps[propKey];
const lastProp = lastProps != null ? lastProps[propKey] : undefined;
const lastProp = lastProps[propKey];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking about moving carefully, is this change related to the text content change? Could we send this out separately?

I know that's tip toeing quite a bit. Just trying to figure out how to move forward with confidence :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good eye :P yeah it's not related to the one change, just another thing I noticed. I did split it out by commit but we can do separate PR's

No harm in being intentional about the changes!

@jquense jquense changed the title Minor code pruning Remove setTextContent helper Dec 19, 2017
@syranide
Copy link
Contributor

@jquense setTextContent should be IE8 only.

@syranide
Copy link
Contributor

@jquense EDIT: Specifically because innerText in IE8 behaves unacceptably and actually messes with the text being set.

@syranide
Copy link
Contributor

@jquense Sorry for the spam, but here's my origin PR #1864 :)

@jquense
Copy link
Contributor Author

jquense commented Dec 20, 2017

Awesome, thanks for the context @syranide

Anyone else wanna jump in? otherwise good to go?

@gaearon
Copy link
Collaborator

gaearon commented Dec 20, 2017

I don't think this code is currently IE8-motivated. The IE8 part was removed in #11331.

The current code using nodeValue was performance-motivated. @trueadm added it in #7005. If we can run benchmarks and confirm it's no longer causing a difference in modern browsers I think we can remove it, but sounds like we should at least verify that.

@jquense
Copy link
Contributor Author

jquense commented Dec 20, 2017

that's really interesting. The idea is that if the content is a single text node it's faster to set nodeValue there? I'd be happy try and verify, at the very least I'll update the comment :)

@trueadm
Copy link
Contributor

trueadm commented Dec 20, 2017

It's still much faster to update a single text node via nodeValue than textContent for updates. textContent is faster on initial, as it creates a child TextNode for you. Using textContent for updates is expensive, as it creates a new TextNode and replaces the existing one, plus it has to deal with cases such as null (which removes all child nodes).

@jquense
Copy link
Contributor Author

jquense commented Dec 20, 2017

TIL :)

Thanks for the clarification (and sorry i didn't find the previous work on this before updating!)

@syranide
Copy link
Contributor

syranide commented Dec 20, 2017

@trueadm Just curious, could it possibly be faster with .data even? Considering that's a property of the Text-node itself rather than the Element.

@trueadm
Copy link
Contributor

trueadm commented Dec 20, 2017

@syranide I tried with data but it wasn't as fast as nodeValue. Might be worth benchmarking that again though – I've not tried data for a while. Furthermore, you can pass a string or number to both textContent and nodeValue. They both sanitize to string anyway.

@jquense jquense changed the title Remove setTextContent helper Clarify reason for setTextContent helper Dec 20, 2017
@@ -736,7 +737,7 @@ const DOMRenderer = ReactFiberReconciler({
},

resetTextContent(domElement: Instance): void {
domElement.textContent = '';
setTextContent(domElement, '');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Semi related:
#11609

commitTextUpdate throws in some cases in IE9. I wonder if using this method there would fix it.

@trueadm
Copy link
Contributor

trueadm commented Dec 22, 2017

I can also confirm innerText is faster than textContent for creating the initial text and also for updates (in all browsers). Be careful when benchmarking on Chrome, it caches the value and does an auto diff for textContent so you'll need to change the string each time for benchmarking purposes.

@syranide
Copy link
Contributor

@trueadm Just for posterity, you should absolutely not use innerText instead of textContent because they are not identical.

@trueadm
Copy link
Contributor

trueadm commented Dec 23, 2017

@gaearon gaearon merged commit 4e044f5 into master Jan 5, 2018
@gaearon gaearon deleted the prune branch January 5, 2018 18:10
yenshih pushed a commit to yenshih/react that referenced this pull request Jan 6, 2018
* Update comment on setTextContent

update the comment explaining the reason for the helper

* Use `setTextContent` in ReactDOM for consistency
ManasJayanth pushed a commit to ManasJayanth/react that referenced this pull request Jan 12, 2018
* Update comment on setTextContent

update the comment explaining the reason for the helper

* Use `setTextContent` in ReactDOM for consistency
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants