Skip to content

Commit

Permalink
Adds React event component and React event target support to SSR rend…
Browse files Browse the repository at this point in the history
…erer (#15242)

* Adds React event component and React event target support to SSR renderer
  • Loading branch information
trueadm authored Mar 28, 2019
1 parent c7a2dce commit c6f3524
Show file tree
Hide file tree
Showing 2 changed files with 250 additions and 1 deletion.
29 changes: 29 additions & 0 deletions packages/react-dom/src/server/ReactPartialRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import ReactSharedInternals from 'shared/ReactSharedInternals';
import {
warnAboutDeprecatedLifecycles,
enableSuspenseServerRenderer,
enableEventAPI,
} from 'shared/ReactFeatureFlags';

import {
Expand All @@ -36,6 +37,8 @@ import {
REACT_CONTEXT_TYPE,
REACT_LAZY_TYPE,
REACT_MEMO_TYPE,
REACT_EVENT_COMPONENT_TYPE,
REACT_EVENT_TARGET_TYPE,
} from 'shared/ReactSymbols';

import {
Expand Down Expand Up @@ -1162,6 +1165,32 @@ class ReactDOMServerRenderer {
this.stack.push(frame);
return '';
}
case REACT_EVENT_COMPONENT_TYPE:
case REACT_EVENT_TARGET_TYPE: {
if (enableEventAPI) {
const nextChildren = toArray(
((nextChild: any): ReactElement).props.children,
);
const frame: Frame = {
type: null,
domNamespace: parentNamespace,
children: nextChildren,
childIndex: 0,
context: context,
footer: '',
};
if (__DEV__) {
((frame: any): FrameDev).debugElementStack = [];
}
this.stack.push(frame);
return '';
}
invariant(
false,
'ReactDOMServer does not yet support the event API.',
);
}
// eslint-disable-next-line-no-fallthrough
case REACT_LAZY_TYPE:
invariant(
false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
* LICENSE file in the root directory of this source tree.
*
* @emails react-core
* @jest-environment node
*/

'use strict';
Expand All @@ -16,6 +15,8 @@ let Scheduler;
let ReactFeatureFlags;
let EventComponent;
let ReactTestRenderer;
let ReactDOM;
let ReactDOMServer;
let EventTarget;
let ReactEvents;

Expand Down Expand Up @@ -51,6 +52,16 @@ function initTestRenderer() {
ReactTestRenderer = require('react-test-renderer');
}

function initReactDOM() {
init();
ReactDOM = require('react-dom');
}

function initReactDOMServer() {
init();
ReactDOMServer = require('react-dom/server');
}

// This is a new feature in Fiber so I put it in its own test file. It could
// probably move to one of the other test files once it is official.
describe('ReactFiberEvents', () => {
Expand Down Expand Up @@ -358,4 +369,213 @@ describe('ReactFiberEvents', () => {
);
});
});

describe('ReactDOM', () => {
beforeEach(() => {
initReactDOM();
EventComponent = createReactEventComponent();
EventTarget = ReactEvents.TouchHitTarget;
});

it('should render a simple event component with a single child', () => {
const Test = () => (
<EventComponent>
<div>Hello world</div>
</EventComponent>
);
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div>Hello world</div>');
});

it('should warn when an event component has a direct text child', () => {
const Test = () => <EventComponent>Hello world</EventComponent>;

expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
'Wrap the child text "Hello world" in an element.',
);
});

it('should warn when an event component has a direct text child #2', () => {
const ChildWrapper = () => 'Hello world';
const Test = () => (
<EventComponent>
<ChildWrapper />
</EventComponent>
);

expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: React event components cannot have text DOM nodes as children. ' +
'Wrap the child text "Hello world" in an element.',
);
});

it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<div>Hello world</div>
</EventTarget>
</EventComponent>
);

const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<div>Hello world</div>');

const Test2 = () => (
<EventComponent>
<EventTarget>
<span>I am now a span</span>
</EventTarget>
</EventComponent>
);

ReactDOM.render(<Test2 />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<span>I am now a span</span>');
});

it('should warn when an event target has a direct text child', () => {
const Test = () => (
<EventComponent>
<EventTarget>Hello world</EventTarget>
</EventComponent>
);

expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev([
'Warning: validateDOMNesting: React event targets cannot have text DOM nodes as children. ' +
'Wrap the child text "Hello world" in an element.',
'Warning: <TouchHitTarget> must have a single DOM element as a child. Found no children.',
]);
});

it('should warn when an event target has a direct text child #2', () => {
const ChildWrapper = () => 'Hello world';
const Test = () => (
<EventComponent>
<EventTarget>
<ChildWrapper />
</EventTarget>
</EventComponent>
);

expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev([
'Warning: validateDOMNesting: React event targets cannot have text DOM nodes as children. ' +
'Wrap the child text "Hello world" in an element.',
'Warning: <TouchHitTarget> must have a single DOM element as a child. Found no children.',
]);
});

it('should warn when an event target has more than one child', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<span>Child 1</span>
<span>Child 2</span>
</EventTarget>
</EventComponent>
);

const container = document.createElement('div');
expect(() => {
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: <TouchHitTarget> must only have a single DOM element as a child. Found many children.',
);
// This should not fire a warning, as this is now valid.
const Test2 = () => (
<EventComponent>
<EventTarget>
<span>Child 1</span>
</EventTarget>
</EventComponent>
);
ReactDOM.render(<Test2 />, container);
expect(Scheduler).toFlushWithoutYielding();
expect(container.innerHTML).toBe('<span>Child 1</span>');
});

it('should warn if an event target is not a direct child of an event component', () => {
const Test = () => (
<EventComponent>
<div>
<EventTarget>
<span>Child 1</span>
</EventTarget>
</div>
</EventComponent>
);

expect(() => {
const container = document.createElement('div');
ReactDOM.render(<Test />, container);
expect(Scheduler).toFlushWithoutYielding();
}).toWarnDev(
'Warning: validateDOMNesting: React event targets must be direct children of event components.',
);
});
});

describe('ReactDOMServer', () => {
beforeEach(() => {
initReactDOMServer();
EventComponent = createReactEventComponent();
EventTarget = ReactEvents.TouchHitTarget;
});

it('should render a simple event component with a single child', () => {
const Test = () => (
<EventComponent>
<div>Hello world</div>
</EventComponent>
);
const output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe('<div>Hello world</div>');
});

it('should render a simple event component with a single event target', () => {
const Test = () => (
<EventComponent>
<EventTarget>
<div>Hello world</div>
</EventTarget>
</EventComponent>
);

let output = ReactDOMServer.renderToString(<Test />);
expect(output).toBe('<div>Hello world</div>');

const Test2 = () => (
<EventComponent>
<EventTarget>
<span>I am now a span</span>
</EventTarget>
</EventComponent>
);

output = ReactDOMServer.renderToString(<Test2 />);
expect(output).toBe('<span>I am now a span</span>');
});
});
});

0 comments on commit c6f3524

Please sign in to comment.