-
Notifications
You must be signed in to change notification settings - Fork 48.8k
Refactor shouldSetTextContent & Add tests (#11789) #11792
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
Conversation
98d59fd
to
c75f47f
Compare
} | ||
|
||
if (typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null) { | ||
if (typeof props.dangerouslySetInnerHTML.__html === 'string') { |
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.
Should number
be allowed?
return false; | ||
} else if ( | ||
typeof props.dangerouslySetInnerHTML.__html === 'object' && | ||
typeof props.dangerouslySetInnerHTML.__html.toString === 'function' |
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.
I don't understand how this could work. Any JS object has toString defined.
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.
Object.create(null)
maybe ?
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.
Ah...
> typeof ({}).toString
'function'
@gaearon good catch, could refactor to use .hasOwnProperty
? :)
> ({}).hasOwnProperty('toString')
false
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.
It could be inherited from something else. I think in general trying to detect a custom toString
is a flawed approach.
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.
Hmm yeah, so maybe back to square 1? Just check for an object, with a check for the existence of toString
for corner cases like Object.create(null)
?
I'm sorry but I'm spacing out a bit. Can you explain me what the problem is in the existing code, and what is your high-level approach to fixing it? |
The issue is outlined in detail here: #11789 but tl;dr: open the console and load this repro: https://codesandbox.io/s/vqkq34o965 With the following:
When doing SSR, we get a console mismatch warning, and the component turns blank. This is noteworthy because if we just use I did some digging into why this occurs, and if my understanding is correct, it is because |
What is React 15 behavior for this? |
Appears to work as expected with React 15, using (no console errors and the component renders correctly) |
It's not exactly equivalent since it's not doing hydration. (React 15 wanted a special attribute and 1:1 markup match for that.) Although 15 didn't touch the DOM at all during hydration so maybe it doesn't matter. Can you try creating a full hydrating example with 15, still? |
What did React 15 do for |
Sorry, updated to use the markup generated from
|
I'm okay with a fix that keeps React 15 behavior then. |
ReactDOM: size: 🔺+0.1%, gzip: 🔺+0.1% Details of bundled changes.Comparing: 7c39328...0ab6817 react-dom
Generated by 🚫 dangerJS |
Hi @gaearon - I've changed the logic slightly to clarify the intended behavior - in that we no longer explicitly check for Tests pass, and I built locally and verified that I still see the (fwiw, when I built locally with my old diff, I still saw the same Can you think of anything else I might be missing here, or any other tests I could add? Lot of moving parts here 😌 Thanks! |
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.
Need to fix the null
comparison, add more tests, and a few other nits.
// the `toString` method of objects. (#11792) | ||
if ( | ||
typeof props.dangerouslySetInnerHTML.__html === 'object' && | ||
props.dangerouslySetInnerHTML.__html !== 'null' |
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.
Why are we comparing to a string literal here? Is this a bug? In that case it means we're missing a test that would have caught it.
return true; | ||
} | ||
|
||
if ( |
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.
Overall: we are reading props.dangerouslySetInnerHTML
a lot of times here. I know old code did too, but this makes reading a bit difficult in all further conditions. Mind extracting it to a variable?
@@ -197,6 +197,16 @@ describe('ReactDOMTextComponent', () => { | |||
expect(el.textContent).toBe(''); | |||
}); | |||
|
|||
it('can reconcile text from pre-rendered markup using dangerouslySetInnerHTML and an object with toString', () => { |
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.
Can we add some tests to ReactDOMServerIntegration*
suite instead? They will test all possible combinations and verify those match between client-only/server-only/hydration scenarios.
) { | ||
return true; | ||
} | ||
} |
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.
Is it strings and objects specifically that are allowed? What if __html
is a number, for example?
What did React 15 do in this case? Can you point to similar logic there so we can compare the behavior?
This stalled so I'm sending a different PR: #13353 |
This PR adds 2 tests to further clarify the issue raised in #11789
Only the test in
ReactDOMTextComponent-test.js
fails.It seems like either both tests should pass, or both tests should fail, depending on the desired behavior of passing an object with a
toString
method todangerouslySetInnerHTML
?Thanks!
Edit: I've refactored
shouldSetTextContent
in order to clarify the logic flow, and to add the fix. Let me know if this looks ok. Thanks!@gaearon