[change] export or replace react-dom methods

This change adds the react-dom methods to the main export, since this is
a Web-only environment (React Native does something similar). It
augments the default render methods in order to move style sheet
management under the control of the library (necessary for
code-splitting support).

Relates to #52
This commit is contained in:
Nicolas Gallagher
2015-12-22 00:21:30 +00:00
parent c850a5fa8c
commit cc10de43eb
6 changed files with 103 additions and 26 deletions

View File

@@ -32,8 +32,9 @@ npm install --save react react-dom react-native-web
## Example
React Native for Web exports its components and a reference to the `React`
installation. Styles are defined with, and used as JavaScript objects.
React Native for Web exports its components, a reference to the `react`
installation, and the `react-dom` methods (customized for Web). Styles are defined
with, and used as JavaScript objects.
Component:
@@ -87,22 +88,20 @@ const styles = StyleSheet.create({
})
```
Pre-render styles on the server:
Pre-rendering on the server automatically includes your app styles:
```js
// server.js
import App from './components/App'
import React, { StyleSheet } from 'react-native-web'
import React from 'react-native-web'
const html = React.renderToString(<App />);
const css = StyleSheet.renderToString();
const Html = () => (
<html>
<head>
<meta charSet="utf-8" />
<meta content="initial-scale=1,width=device-width" name="viewport" />
<style id="react-stylesheet" dangerouslySetInnerHTML={{ __html: css } />
</head>
<body>
<div id="react-root" dangerouslySetInnerHTML={{ __html: html }} />
@@ -111,19 +110,14 @@ const Html = () => (
)
```
Render styles on the client:
Rendering on the client automatically includes your app styles:
```js
// client.js
import App from './components/App'
import React, { StyleSheet } from 'react-native-web'
import ReactDOM from 'react-dom'
import React from 'react-native-web'
const reactRoot = document.getElementById('react-root')
const reactStyleSheet = document.getElementById('react-stylesheet')
ReactDOM.render(<App />, reactRoot)
reactStyleSheet.textContent = StyleSheet.renderToString()
React.render(<App />, document.getElementById('react-root'))
```
## APIs

View File

@@ -7,7 +7,8 @@ module.exports = {
},
externals: [{
'react': true,
'react-dom': true
'react-dom': true,
'react-dom/server': true
}],
output: {
filename: 'react-native-web.js',

View File

@@ -2,7 +2,5 @@
<meta charset="utf-8">
<title>React Native for Web</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="The core React Native components adapted and expanded upon for the web">
<style id="react-stylesheet"></style>
<div id="react-root"></div>
<script src="/examples.js"></script>

View File

@@ -2,8 +2,7 @@ import { MediaProvider, matchMedia } from 'react-media-queries'
import App from './components/App'
import createGetter from 'react-media-queries/lib/createMediaQueryGetter'
import createListener from 'react-media-queries/lib/createMediaQueryListener'
import React, { StyleSheet } from '../src'
import ReactDOM from 'react-dom'
import React from '../src'
const mediaQueries = {
small: '(min-width: 300px)',
@@ -12,11 +11,9 @@ const mediaQueries = {
}
const ResponsiveApp = matchMedia()(App)
ReactDOM.render(
React.render(
<MediaProvider getMedia={createGetter(mediaQueries)} listener={createListener(mediaQueries)}>
<ResponsiveApp />
</MediaProvider>,
document.getElementById('react-root')
)
document.getElementById('react-stylesheet').textContent = StyleSheet.renderToString()

View File

@@ -0,0 +1,54 @@
/* eslint-env mocha */
import * as utils from '../modules/specHelpers'
import assert from 'assert'
import React from '..'
suite('ReactNativeWeb', () => {
suite('exports', () => {
test('React', () => {
assert.ok(React)
})
test('ReactDOM methods', () => {
assert.ok(React.findDOMNode)
assert.ok(React.render)
assert.ok(React.unmountComponentAtNode)
})
test('ReactDOM/server methods', () => {
assert.ok(React.renderToString)
assert.ok(React.renderToStaticMarkup)
})
})
suite('render methods', () => {
const id = 'test'
let div
setup(() => {
div = document.createElement('div')
div.id = id
document.body.appendChild(div)
})
teardown(() => {
document.body.removeChild(div)
})
test('"render" creates style sheet', () => {
React.render(<div />, div)
assert.ok(document.getElementById('react-stylesheet'))
})
test('"renderToString" creates style sheet', () => {
const result = React.renderToString(<div />)
assert.ok(result.indexOf('react-stylesheet') > -1)
})
test('"renderToStaticMarkup" creates style sheet', () => {
const result = React.renderToStaticMarkup(<div />)
assert.ok(result.indexOf('react-stylesheet') > -1)
})
})
})

View File

@@ -1,5 +1,8 @@
import React from 'react'
import ReactDOM from 'react-dom'
import ReactDOMServer from 'react-dom/server'
// api
import StyleSheet from './modules/StyleSheet'
// components
@@ -11,7 +14,35 @@ import TextInput from './components/TextInput'
import Touchable from './components/Touchable'
import View from './components/View'
const renderStyle = () => {
return `<style id='react-stylesheet'>${StyleSheet.renderToString()}</style>`
}
const render = (element, container, callback) => {
const styleElement = document.getElementById('react-stylesheet')
if (!styleElement) {
const style = renderStyle()
container.insertAdjacentHTML('beforebegin', style)
}
return ReactDOM.render(element, container, callback)
}
const renderToString = (element) => {
const style = renderStyle()
const html = ReactDOMServer.renderToString(element)
return `${style}\n${html}`
}
const renderToStaticMarkup = (element) => {
const style = renderStyle()
const html = ReactDOMServer.renderToStaticMarkup(element)
return `${style}\n${html}`
}
const ReactNative = {
// apis
StyleSheet,
// components
Image,
ListView,
@@ -21,11 +52,13 @@ const ReactNative = {
Touchable,
View,
// apis
StyleSheet,
// React
...React
...React,
...ReactDOM,
...ReactDOMServer,
render,
renderToString,
renderToStaticMarkup
}
module.exports = ReactNative