Refactor shouldSetTextContent & Add tests (#11789)#11792
Refactor shouldSetTextContent & Add tests (#11789)#11792magicmark wants to merge 1 commit intofacebook:masterfrom
Conversation
98d59fd to
c75f47f
Compare
| } | ||
|
|
||
| if (typeof props.dangerouslySetInnerHTML === 'object' && props.dangerouslySetInnerHTML !== null) { | ||
| if (typeof props.dangerouslySetInnerHTML.__html === 'string') { |
| return false; | ||
| } else if ( | ||
| typeof props.dangerouslySetInnerHTML.__html === 'object' && | ||
| typeof props.dangerouslySetInnerHTML.__html.toString === 'function' |
There was a problem hiding this comment.
I don't understand how this could work. Any JS object has toString defined.
There was a problem hiding this comment.
Object.create(null) maybe ?
There was a problem hiding this comment.
Ah...
> typeof ({}).toString
'function'
@gaearon good catch, could refactor to use .hasOwnProperty? :)
> ({}).hasOwnProperty('toString')
false
There was a problem hiding this comment.
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.
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! |
gaearon
left a comment
There was a problem hiding this comment.
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.
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.
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?
| 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.
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.
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.jsfails.It seems like either both tests should pass, or both tests should fail, depending on the desired behavior of passing an object with a
toStringmethod todangerouslySetInnerHTML?Thanks!
Edit: I've refactored
shouldSetTextContentin order to clarify the logic flow, and to add the fix. Let me know if this looks ok. Thanks!@gaearon