Skip to content

Commit

Permalink
add isHydrating argument and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Maxime Nory committed May 31, 2018
1 parent 1684cfc commit 1476d65
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -348,9 +348,13 @@ describe('ReactDOMServerIntegration', () => {
ControlledSelect;
beforeEach(() => {
ControlledInput = class extends React.Component {
static defaultProps = {
type: 'text',
initialValue: 'Hello',
};
constructor() {
super();
this.state = {value: 'Hello'};
super(...arguments);
this.state = {value: this.props.initialValue};
}
handleChange(event) {
if (this.props.onChange) {
Expand All @@ -361,6 +365,7 @@ describe('ReactDOMServerIntegration', () => {
render() {
return (
<input
type={this.props.type}
value={this.state.value}
onChange={this.handleChange.bind(this)}
/>
Expand Down Expand Up @@ -551,6 +556,27 @@ describe('ReactDOMServerIntegration', () => {
expect(changeCount).toBe(0);
});

it('should not blow away user-interaction on successful reconnect to an uncontrolled range input', () =>
testUserInteractionBeforeClientRender(
<input type="text" defaultValue="0.5" />,
'0.5',
'1',
));

it('should not blow away user-interaction on successful reconnect to a controlled range input', async () => {
let changeCount = 0;
await testUserInteractionBeforeClientRender(
<ControlledInput
type="range"
initialValue="0.25"
onChange={() => changeCount++}
/>,
'0.25',
'1',
);
expect(changeCount).toBe(0);
});

it('should not blow away user-entered text on successful reconnect to an uncontrolled checkbox', () =>
testUserInteractionBeforeClientRender(
<input type="checkbox" defaultChecked={true} />,
Expand Down
4 changes: 2 additions & 2 deletions packages/react-dom/src/client/ReactDOMFiberComponent.js
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ export function setInitialProperties(
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
inputValueTracking.track((domElement: any));
ReactDOMFiberInput.postMountWrapper(domElement, rawProps);
ReactDOMFiberInput.postMountWrapper(domElement, rawProps, false);
break;
case 'textarea':
// TODO: Make sure we check if this is still unmounted or do any clean
Expand Down Expand Up @@ -1077,7 +1077,7 @@ export function diffHydratedProperties(
// TODO: Make sure we check if this is still unmounted or do any clean
// up necessary since we never stop tracking anymore.
inputValueTracking.track((domElement: any));
ReactDOMFiberInput.postMountWrapper(domElement, rawProps);
ReactDOMFiberInput.postMountWrapper(domElement, rawProps, true);
break;
case 'textarea':
// TODO: Make sure we check if this is still unmounted or do any clean
Expand Down
20 changes: 11 additions & 9 deletions packages/react-dom/src/client/ReactDOMFiberInput.js
Original file line number Diff line number Diff line change
Expand Up @@ -205,27 +205,29 @@ export function updateWrapper(element: Element, props: Object) {
}
}

export function postMountWrapper(element: Element, props: Object) {
export function postMountWrapper(element: Element, props: Object, isHydrating: Boolean) {
const node = ((element: any): InputWithWrapperState);

if (props.hasOwnProperty('value') || props.hasOwnProperty('defaultValue')) {
const initialValue = '' + node._wrapperState.initialValue;

// With range inputs node.value may be a default value calculated from the
// min/max attributes. This ensures that node.value is set with the correct
// value coming from props.
const currentValue = props.type === 'range' ? '' : node.value;
let currentValue;
if (isHydrating) {
currentValue = node.value;
} else {
// With range inputs node.value may be a default value calculated from the
// min/max attributes. This ensures that node.value is set with the correct
// value coming from props.
currentValue = props.type === 'range' ? '' : node.value;
}

// Do not assign value if it is already set. This prevents user text input
// from being lost during SSR hydration.
if (currentValue === '') {
if (!node.hasAttribute('value')) {
// Do not re-assign the value property if there is no change. This
// potentially avoids a DOM write and prevents Firefox (~60.0.1) from
// prematurely marking required inputs as invalid
if (initialValue !== currentValue) {
node.value = initialValue;
} else if (props.type === 'range') {
node.value = initialValue;
}
}

Expand Down

0 comments on commit 1476d65

Please sign in to comment.