Keep autoFocus attribute in the DOM (#11192)
* Keep autoFocus attribute in the DOM * Don't emit autoFocus attribute on the client * Test that hydration doesn't call focus * Add autoFocus to SSR fixture
This commit is contained in:
parent
b75be6a363
commit
2228f497f3
|
@ -2,6 +2,11 @@ import React, {Component} from 'react';
|
|||
|
||||
import './Page.css';
|
||||
|
||||
const autofocusedInputs = [
|
||||
<input key="0" autoFocus placeholder="Has auto focus" />,
|
||||
<input key="1" autoFocus placeholder="Has auto focus" />,
|
||||
];
|
||||
|
||||
export default class Page extends Component {
|
||||
state = {active: false};
|
||||
handleClick = e => {
|
||||
|
@ -18,9 +23,16 @@ export default class Page extends Component {
|
|||
<p suppressHydrationWarning={true}>
|
||||
A random number: {Math.random()}
|
||||
</p>
|
||||
<p>
|
||||
Autofocus on page load: {autofocusedInputs}
|
||||
</p>
|
||||
<p>
|
||||
{!this.state.active ? link : 'Thanks!'}
|
||||
</p>
|
||||
{this.state.active &&
|
||||
<p>
|
||||
Autofocus on update: {autofocusedInputs}
|
||||
</p>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -54,6 +54,7 @@ var registrationNameModules = EventPluginRegistry.registrationNameModules;
|
|||
var DANGEROUSLY_SET_INNER_HTML = 'dangerouslySetInnerHTML';
|
||||
var SUPPRESS_CONTENT_EDITABLE_WARNING = 'suppressContentEditableWarning';
|
||||
var SUPPRESS_HYDRATION_WARNING = 'suppressHydrationWarning';
|
||||
var AUTOFOCUS = 'autoFocus';
|
||||
var CHILDREN = 'children';
|
||||
var STYLE = 'style';
|
||||
var HTML = '__html';
|
||||
|
@ -286,6 +287,9 @@ function setInitialDOMProperties(
|
|||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (propKey === AUTOFOCUS) {
|
||||
// We polyfill it separately on the client during commit.
|
||||
// We blacklist it here rather than in the property list because we emit it in SSR.
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
if (nextProp != null) {
|
||||
if (__DEV__ && typeof nextProp !== 'function') {
|
||||
|
@ -681,6 +685,8 @@ var ReactDOMFiberComponent = {
|
|||
propKey === SUPPRESS_HYDRATION_WARNING
|
||||
) {
|
||||
// Noop
|
||||
} else if (propKey === AUTOFOCUS) {
|
||||
// Noop. It doesn't work on updates anyway.
|
||||
} else if (registrationNameModules.hasOwnProperty(propKey)) {
|
||||
// This is a special case. If any listener updates we need to ensure
|
||||
// that the "current" fiber pointer gets updated so we need a commit
|
||||
|
|
|
@ -16,7 +16,6 @@ var invariant = require('fbjs/lib/invariant');
|
|||
var RESERVED_PROPS = {
|
||||
children: true,
|
||||
dangerouslySetInnerHTML: true,
|
||||
autoFocus: true,
|
||||
defaultValue: true,
|
||||
defaultChecked: true,
|
||||
innerHTML: true,
|
||||
|
|
|
@ -26,6 +26,7 @@ var HTMLDOMPropertyConfig = {
|
|||
// name warnings.
|
||||
Properties: {
|
||||
allowFullScreen: HAS_BOOLEAN_VALUE,
|
||||
autoFocus: HAS_STRING_BOOLEAN_VALUE,
|
||||
// specifies target context for links with `preload` type
|
||||
async: HAS_BOOLEAN_VALUE,
|
||||
// autoFocus is polyfilled/normalized by AutoFocusUtils
|
||||
|
|
|
@ -351,6 +351,26 @@ describe('ReactDOMServer', () => {
|
|||
expect(numClicks).toEqual(2);
|
||||
});
|
||||
|
||||
// We have a polyfill for autoFocus on the client, but we intentionally don't
|
||||
// want it to call focus() when hydrating because this can mess up existing
|
||||
// focus before the JS has loaded.
|
||||
it('should emit autofocus on the server but not focus() when hydrating', () => {
|
||||
var element = document.createElement('div');
|
||||
element.innerHTML = ReactDOMServer.renderToString(
|
||||
<input autoFocus={true} />,
|
||||
);
|
||||
expect(element.firstChild.autofocus).toBe(true);
|
||||
|
||||
// It should not be called on mount.
|
||||
element.firstChild.focus = jest.fn();
|
||||
ReactDOM.hydrate(<input autoFocus={true} />, element);
|
||||
expect(element.firstChild.focus).not.toHaveBeenCalled();
|
||||
|
||||
// Or during an update.
|
||||
ReactDOM.render(<input autoFocus={true} />, element);
|
||||
expect(element.firstChild.focus).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should throw with silly args', () => {
|
||||
expect(
|
||||
ReactDOMServer.renderToString.bind(ReactDOMServer, {x: 123}),
|
||||
|
|
Loading…
Reference in New Issue