diff --git a/fixtures/dom/public/renderer.js b/fixtures/dom/public/renderer.js index 542580a073..fa8eca8b63 100644 --- a/fixtures/dom/public/renderer.js +++ b/fixtures/dom/public/renderer.js @@ -13,6 +13,30 @@ var renders = 0; var failed = false; + var needsReactDOM = getBooleanQueryParam('needsReactDOM'); + var needsCreateElement = getBooleanQueryParam('needsCreateElement'); + + function unmountComponent(node) { + // ReactDOM was moved into a separate package in 0.14 + if (needsReactDOM) { + ReactDOM.unmountComponentAtNode(node); + } else if (React.unmountComponentAtNode) { + React.unmountComponentAtNode(node); + } else { + // Unmounting for React 0.4 and lower + React.unmountAndReleaseReactRootNode(node); + } + } + + function createElement(value) { + // React.createElement replaced function invocation in 0.12 + if (needsCreateElement) { + return React.createElement(value); + } else { + return value(); + } + } + function getQueryParam(key) { var pattern = new RegExp(key + '=([^&]+)(&|$)'); var matches = window.location.search.match(pattern); @@ -35,20 +59,56 @@ function prerender() { setStatus('Generating markup'); - output.innerHTML = ReactDOMServer.renderToString( - React.createElement(Fixture) - ); + return Promise.resolve() + .then(function() { + const element = createElement(Fixture); - setStatus('Markup only (No React)'); + // Server rendering moved to a separate package along with ReactDOM + // in 0.14.0 + if (needsReactDOM) { + return ReactDOMServer.renderToString(element); + } + + // React.renderComponentToString was renamed in 0.12 + if (React.renderToString) { + return React.renderToString(element); + } + + // React.renderComponentToString became synchronous in React 0.9.0 + if (React.renderComponentToString.length === 1) { + return React.renderComponentToString(element); + } + + // Finally, React 0.4 and lower emits markup in a callback + return new Promise(function(resolve) { + React.renderComponentToString(element, resolve); + }); + }) + .then(function(string) { + output.innerHTML = string; + setStatus('Markup only (No React)'); + }) + .catch(handleError); } function render() { setStatus('Hydrating'); - if (ReactDOM.hydrate) { - ReactDOM.hydrate(React.createElement(Fixture), output); + var element = createElement(Fixture); + + // ReactDOM was split out into another package in 0.14 + if (needsReactDOM) { + // Hydration changed to a separate method in React 16 + if (ReactDOM.hydrate) { + ReactDOM.hydrate(element, output); + } else { + ReactDOM.render(element, output); + } + } else if (React.render) { + // React.renderComponent was renamed in 0.12 + React.render(element, output); } else { - ReactDOM.render(React.createElement(Fixture), output); + React.renderComponent(element, output); } setStatus(renders > 0 ? 'Re-rendered (' + renders + 'x)' : 'Hydrated'); @@ -85,17 +145,17 @@ setStatus('Failed'); output.innerHTML = 'Please name your root component "Fixture"'; } else { - prerender(); - - if (getBooleanQueryParam('hydrate')) { - render(); - } + prerender().then(function() { + if (getBooleanQueryParam('hydrate')) { + render(); + } + }); } } function reloadFixture(code) { renders = 0; - ReactDOM.unmountComponentAtNode(output); + unmountComponent(output); injectFixture(code); } @@ -109,12 +169,12 @@ loadScript(getQueryParam('reactPath')) .then(function() { - return getBooleanQueryParam('needsReactDOM') - ? loadScript(getQueryParam('reactDOMPath')) - : null; - }) - .then(function() { - return loadScript(getQueryParam('reactDOMServerPath')); + if (needsReactDOM) { + return Promise.all([ + loadScript(getQueryParam('reactDOMPath')), + loadScript(getQueryParam('reactDOMServerPath')), + ]); + } }) .then(function() { if (failed) { diff --git a/fixtures/dom/src/components/App.js b/fixtures/dom/src/components/App.js index 5b0de92e07..e54cc333d8 100644 --- a/fixtures/dom/src/components/App.js +++ b/fixtures/dom/src/components/App.js @@ -4,13 +4,15 @@ import '../style.css'; const React = window.React; -function App() { - return ( -
-
- -
- ); +class App extends React.Component { + render() { + return ( +
+
+ +
+ ); + } } export default App; diff --git a/fixtures/dom/src/components/Header.js b/fixtures/dom/src/components/Header.js index 8fc03246e8..74af700e27 100644 --- a/fixtures/dom/src/components/Header.js +++ b/fixtures/dom/src/components/Header.js @@ -1,5 +1,6 @@ import {parse, stringify} from 'query-string'; -import getVersionTags from '../tags'; +import VersionPicker from './VersionPicker'; + const React = window.React; class Header extends React.Component { @@ -9,18 +10,12 @@ class Header extends React.Component { const version = query.version || 'local'; const production = query.production || false; const versions = [version]; + this.state = {version, versions, production}; } - componentWillMount() { - getVersionTags().then(tags => { - let versions = tags.map(tag => tag.name.slice(1)); - versions = [`local`, ...versions]; - this.setState({versions}); - }); - } - handleVersionChange(event) { + handleVersionChange(version) { const query = parse(window.location.search); - query.version = event.target.value; + query.version = version; if (query.version === 'local') { delete query.version; } @@ -48,7 +43,10 @@ class Header extends React.Component { width="20" height="20" /> - DOM Test Fixtures (v{React.version}) + + DOM Test Fixtures (v + {React.version}) +
@@ -90,17 +88,14 @@ class Header extends React.Component { -
diff --git a/fixtures/dom/src/components/VersionPicker.js b/fixtures/dom/src/components/VersionPicker.js new file mode 100644 index 0000000000..fcccf0947b --- /dev/null +++ b/fixtures/dom/src/components/VersionPicker.js @@ -0,0 +1,41 @@ +import getVersionTags from '../tags'; + +const React = window.React; + +class VersionPicker extends React.Component { + constructor(props, context) { + super(props, context); + const version = props.version || 'local'; + const versions = [version]; + this.state = {versions}; + } + + componentWillMount() { + getVersionTags().then(tags => { + let versions = tags.map(tag => tag.name.slice(1)); + versions = [`local`, ...versions]; + this.setState({versions}); + }); + } + + onChange = event => { + this.props.onChange(event.target.value); + }; + + render() { + const {version, id, name} = this.props; + const {versions} = this.state; + + return ( + + ); + } +} + +export default VersionPicker; diff --git a/fixtures/dom/src/components/fixtures/hydration/Code.js b/fixtures/dom/src/components/fixtures/hydration/Code.js index 26d93b4697..55c44a8c3a 100644 --- a/fixtures/dom/src/components/fixtures/hydration/Code.js +++ b/fixtures/dom/src/components/fixtures/hydration/Code.js @@ -1,3 +1,5 @@ +import {findDOMNode} from '../../../find-dom-node'; + const React = window.React; export class CodeEditor extends React.Component { @@ -6,6 +8,8 @@ export class CodeEditor extends React.Component { } componentDidMount() { + this.textarea = findDOMNode(this); + // Important: CodeMirror incorrectly lays out the editor // if it executes before CSS has loaded // https://github.com/graphql/graphiql/issues/33#issuecomment-318188555 @@ -44,7 +48,6 @@ export class CodeEditor extends React.Component { render() { return (