From 606e329d8305cb354b969da1baf56832c2fe96d7 Mon Sep 17 00:00:00 2001 From: benpptung Date: Wed, 9 May 2018 17:14:38 +0800 Subject: [PATCH 1/4] initial draft --- text/0000-ssrReconciliation.md | 94 ++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 text/0000-ssrReconciliation.md diff --git a/text/0000-ssrReconciliation.md b/text/0000-ssrReconciliation.md new file mode 100644 index 00000000..fbcfbdb3 --- /dev/null +++ b/text/0000-ssrReconciliation.md @@ -0,0 +1,94 @@ +- Start Date: 2018-05-9 +- RFC PR: +- React Issue: + +# Summary + +Give the developer a chance to `intentially` patch up the mismatches during hydration. + +# Basic example + +``` + +constructor(props) { + super(props) + + this.styles = Object.defineProperties({}, { + 'container': { get: _=> { + return typeof window == 'undefined' + ? { height: 300 } + : { height: this.props.viewsize.height * 0.67} + }} + }) +} + +render() { + let s = this.styles + return
+} + + +``` + +# Motivation + +React expects that the rendered content is identical between the server and the client. This is important for performance reasons. If you intentionally need to render something different on the server and the client, you have to do a two-pass rendering like [facebook/react/issues/8017#issuecomment-256351955](https://github.com/facebook/react/issues/8017#issuecomment-256351955) + + +If an attribute is derived from screen size, since we don't know the real screen size in the server side, we might do a 2 pass rendering like following: + +``` +constructor(props) { + super(props) + this.state = { hasMounted: false } + + this.styles = Object.defineProperties({}, { + 'container': { get: _=> { + if (typeof window == 'undefined') return { height: 300 } + let height = this.props.viewsize.height * 0.67 + return this.state.hasMounted ? { height } : { height: height - 1 } + }} + }) +} + +componentDidMount() { + this.setState({ hasMounted: true }) +} + +render() { + let s = this.styles + return ( +
+
+ ) +} +``` + +In the above code, I demonstrate that I have to intentionally render a wrong height initially in the browser so I can update it in the second run, or the DOM will keep inconsistent with the vDOM. + +This is because if the 2 renderings keep unchanged in vDOM, React won't update the DOM. 2 pass rendering to patch up the mismatches comes with some drawbacks: + +1. Introduce unnecessary 2nd rendering + +2. The component will do 2 pass rendering in every mounting even it is not in hydration. + + +# Detailed design + +Design a `ssrReconciliation={true}` attribute, or something like that, e.g. ssrPatchUp={true} for the developer to ask React to patch up if a single element's attribute or text content is unavoidably different between the server and the client during hydration. + +# Drawbacks + +Increased validating cost, and the developer might overuse this to prevent any mismatch. + +# Alternatives + +Unsure + +# Adoption strategy + +This is not a breaking change. + +# How we teach this + +Update hydrate() to replace two-pass rendering by this new attribute. \ No newline at end of file From 887cd7735d846979f53baaabc78f598cd482beb0 Mon Sep 17 00:00:00 2001 From: benpptung Date: Wed, 9 May 2018 17:20:05 +0800 Subject: [PATCH 2/4] update --- text/0000-ssrReconciliation.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/text/0000-ssrReconciliation.md b/text/0000-ssrReconciliation.md index fbcfbdb3..7a8ba3cf 100644 --- a/text/0000-ssrReconciliation.md +++ b/text/0000-ssrReconciliation.md @@ -66,7 +66,7 @@ render() { In the above code, I demonstrate that I have to intentionally render a wrong height initially in the browser so I can update it in the second run, or the DOM will keep inconsistent with the vDOM. -This is because if the 2 renderings keep unchanged in vDOM, React won't update the DOM. 2 pass rendering to patch up the mismatches comes with some drawbacks: +This is because if the 2 renderings keep unchanged in vDOM, React won't update the DOM. Two pass rendering to patch up the mismatches comes with some drawbacks: 1. Introduce unnecessary 2nd rendering @@ -79,7 +79,7 @@ Design a `ssrReconciliation={true}` attribute, or something like that, e.g. ssrP # Drawbacks -Increased validating cost, and the developer might overuse this to prevent any mismatch. +Increased validating cost during hydration, and the developer might overuse this to prevent any mismatch in the future. # Alternatives From 912e855ffa4f7dda7ee66e8911754fdcc5622e80 Mon Sep 17 00:00:00 2001 From: benpptung Date: Wed, 9 May 2018 19:31:58 +0800 Subject: [PATCH 3/4] update --- text/0000-ssrReconciliation.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/text/0000-ssrReconciliation.md b/text/0000-ssrReconciliation.md index 7a8ba3cf..d2d5e618 100644 --- a/text/0000-ssrReconciliation.md +++ b/text/0000-ssrReconciliation.md @@ -71,11 +71,13 @@ This is because if the 2 renderings keep unchanged in vDOM, React won't update t 1. Introduce unnecessary 2nd rendering 2. The component will do 2 pass rendering in every mounting even it is not in hydration. - + +3. Limited to stateful component. # Detailed design -Design a `ssrReconciliation={true}` attribute, or something like that, e.g. ssrPatchUp={true} for the developer to ask React to patch up if a single element's attribute or text content is unavoidably different between the server and the client during hydration. +Design a `ssrReconciliation={true}` attribute, or something like that, e.g. ssrPatchUp={true} for the developer to ask React to patch up if a single element's attribute or text content is unavoidably different between the server and the client during hydration. + # Drawbacks From 432c447a3b831d205f631b7681fe3427b2876fc2 Mon Sep 17 00:00:00 2001 From: benpptung Date: Wed, 9 May 2018 22:16:12 +0800 Subject: [PATCH 4/4] markdown jsx syntax --- text/0000-ssrReconciliation.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/text/0000-ssrReconciliation.md b/text/0000-ssrReconciliation.md index d2d5e618..4219c248 100644 --- a/text/0000-ssrReconciliation.md +++ b/text/0000-ssrReconciliation.md @@ -1,5 +1,5 @@ - Start Date: 2018-05-9 -- RFC PR: +- RFC PR: - React Issue: # Summary @@ -8,15 +8,15 @@ Give the developer a chance to `intentially` patch up the mismatches during hydr # Basic example -``` +```jsx constructor(props) { super(props) - + this.styles = Object.defineProperties({}, { 'container': { get: _=> { return typeof window == 'undefined' - ? { height: 300 } + ? { height: 300 } : { height: this.props.viewsize.height * 0.67} }} }) @@ -37,11 +37,11 @@ React expects that the rendered content is identical between the server and the If an attribute is derived from screen size, since we don't know the real screen size in the server side, we might do a 2 pass rendering like following: -``` +```jsx constructor(props) { super(props) this.state = { hasMounted: false } - + this.styles = Object.defineProperties({}, { 'container': { get: _=> { if (typeof window == 'undefined') return { height: 300 } @@ -93,4 +93,4 @@ This is not a breaking change. # How we teach this -Update hydrate() to replace two-pass rendering by this new attribute. \ No newline at end of file +Update hydrate() to replace two-pass rendering by this new attribute.