mirror of
https://github.com/zoriya/react-native-web.git
synced 2026-05-28 00:32:17 +00:00
Update README; add guides to docs
This commit is contained in:
@@ -2,114 +2,56 @@
|
|||||||
|
|
||||||
[![Build Status][travis-image]][travis-url]
|
[![Build Status][travis-image]][travis-url]
|
||||||
[![npm version][npm-image]][npm-url]
|
[![npm version][npm-image]][npm-url]
|
||||||

|

|
||||||
|
|
||||||
[React Native][react-native-url] components and APIs for the Web. Flexbox
|
[React Native][react-native-url] components and APIs for the Web.
|
||||||
layout and JavaScript styling.
|
|
||||||
|
|
||||||
* [Discord: #react-native-web on reactiflux][discord-url]
|
|
||||||
* [Gitter: react-native-web][gitter-url]
|
|
||||||
|
|
||||||
## Table of contents
|
|
||||||
|
|
||||||
* [Quick start](#quick-start)
|
|
||||||
* [Overview](#overview)
|
|
||||||
* [Example](#example)
|
|
||||||
* [APIs](#apis)
|
|
||||||
* [Components](#components)
|
|
||||||
* [Contributing](#contributing)
|
|
||||||
* [Thanks](#thanks)
|
|
||||||
* [License](#license)
|
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
You can [try the latest version on CodePen](http://codepen.io/necolas/pen/PZzwBR).
|
|
||||||
|
|
||||||
To install in your app:
|
To install in your app:
|
||||||
|
|
||||||
```
|
```
|
||||||
npm install --save react@0.14 react-dom@0.14 react-native-web
|
npm install --save react@0.14 react-dom@0.14 react-native-web
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Or [try it on CodePen](http://codepen.io/necolas/pen/PZzwBR).
|
||||||
|
|
||||||
|
Browser support: Chrome, Firefox, Safari >= 7, IE 10, Edge.
|
||||||
|
|
||||||
## Overview
|
## Overview
|
||||||
|
|
||||||
### Importing
|
This is a web implementation of React Native components and APIs. The React
|
||||||
|
Native components are good web application building blocks, and provide a common
|
||||||
|
foundation for component libraries.
|
||||||
|
|
||||||
All API's, components, and a Web-specific `React` are provided by the
|
For example, the [`View`](docs/apis/View.md) component makes it easy to build
|
||||||
`react-native-web` module:
|
common layouts with flexbox, such as stacked and nested boxes with margin and
|
||||||
|
padding. And the [`StyleSheet`](docs/guides/style.md) API converts styles
|
||||||
```js
|
defined in JavaScript to "atomic" CSS.
|
||||||
import React, { Image, StyleSheet, Text, View } from 'react-native-web'
|
|
||||||
```
|
|
||||||
|
|
||||||
### Client-side rendering
|
|
||||||
|
|
||||||
Client-side rendering requires that you use the module's `React` export.
|
|
||||||
`React.render` is a thin wrapper around `ReactDOM.render` that renders your
|
|
||||||
application and the style sheet. Styles are updated if new bundles are loaded
|
|
||||||
asynchronously.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// client.js
|
|
||||||
import App from './components/App'
|
|
||||||
import React from 'react-native-web'
|
|
||||||
|
|
||||||
React.render(<App />, document.getElementById('react-root'))
|
|
||||||
```
|
|
||||||
|
|
||||||
### Server-side rendering
|
|
||||||
|
|
||||||
Server-side rendering is done by calling `React.renderToString` or
|
|
||||||
`React.renderToStaticMarkup`, the output of both includes the style sheet.
|
|
||||||
|
|
||||||
```js
|
|
||||||
// server.js
|
|
||||||
import App from './components/App'
|
|
||||||
import React from 'react-native-web'
|
|
||||||
|
|
||||||
const html = React.renderToString(<App />);
|
|
||||||
|
|
||||||
const Html = () => (
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charSet="utf-8" />
|
|
||||||
<meta content="initial-scale=1,width=device-width" name="viewport" />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="react-root" dangerouslySetInnerHTML={{ __html: html }} />
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Styling
|
|
||||||
|
|
||||||
React Native for Web allows you to [define styles using
|
|
||||||
JavaScript](docs/guides/style.md), either with inline styles or
|
|
||||||
[`StyleSheet.create`](docs/apis/StyleSheet.md).
|
|
||||||
|
|
||||||
The `View` component makes it easy to build common layouts with flexbox, such
|
|
||||||
as stacked and nested boxes with margin and padding. See this [guide to
|
|
||||||
flexbox][flexbox-guide-url].
|
|
||||||
|
|
||||||
### Accessibility
|
|
||||||
|
|
||||||
The most common and best supported [accessibility
|
|
||||||
features](docs/guides/accessibility.md) of the Web are leveraged through 4
|
|
||||||
props available on most components: `accessible`, `accessibilityLabel`,
|
|
||||||
`accessibilityLiveRegion`, and `accessibilityRole`.
|
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
More examples can be found in the [`examples` directory](examples).
|
More examples can be found in the [`examples` directory](examples).
|
||||||
|
|
||||||
```js
|
```js
|
||||||
import React, { Image, StyleSheet, Text, View } from 'react-native-web'
|
import React, { AppRegistry, Image, StyleSheet, Text, View } from 'react-native'
|
||||||
|
|
||||||
|
// Components
|
||||||
const Card = ({ children }) => <View style={styles.card}>{children}</View>
|
const Card = ({ children }) => <View style={styles.card}>{children}</View>
|
||||||
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
|
const Title = ({ children }) => <Text style={styles.title}>{children}</Text>
|
||||||
const Photo = ({ uri }) => <Image source={{ uri }} style={styles.image} />
|
const Photo = ({ uri }) => <Image source={{ uri }} style={styles.image} />
|
||||||
|
const App = () => (
|
||||||
|
<Card>
|
||||||
|
<Title>App Card</Title>
|
||||||
|
<Photo uri="/some-photo.jpg" />
|
||||||
|
</Card>
|
||||||
|
)
|
||||||
|
|
||||||
|
// App registration and rendering
|
||||||
|
AppRegistry.registerComponent('MyApp', () => App)
|
||||||
|
AppRegistry.runApplication('MyApp', { rootTag: document.getElementById('react-root') })
|
||||||
|
|
||||||
|
// Styles
|
||||||
const styles = StyleSheet.create({
|
const styles = StyleSheet.create({
|
||||||
card: {
|
card: {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
@@ -121,73 +63,52 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
image: {
|
image: {
|
||||||
height: 40,
|
height: 40,
|
||||||
marginRight: 10,
|
marginVertical: 10,
|
||||||
width: 40
|
width: 40
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
## APIs
|
## Documentation
|
||||||
|
|
||||||
### [`StyleSheet`](docs/apis/StyleSheet.md)
|
Guides:
|
||||||
|
|
||||||
StyleSheet is a style abstraction that transforms inline styles to CSS on the
|
* [Accessibility](docs/guides/accessibility.md)
|
||||||
client or the server. It provides a minimal CSS reset targeting elements and
|
* [Client and server rendering](docs/guides/rendering.md)
|
||||||
pseudo-elements beyond the reach of React inline styles.
|
* [Direct manipulation](docs/guides/direct-manipulation.md)
|
||||||
|
* [Known issues](docs/guides/known-issues.md)
|
||||||
|
* [React Native](docs/guides/react-native.md)
|
||||||
|
* [Style](docs/guides/style.md)
|
||||||
|
|
||||||
## Components
|
Exported modules:
|
||||||
|
|
||||||
### [`Image`](docs/components/Image.md)
|
* Components
|
||||||
|
* [`ActivityIndicator`](docs/components/ActivityIndicator.md)
|
||||||
An accessibile image component with support for image resizing, default image,
|
* [`Image`](docs/components/Image.md)
|
||||||
and child content.
|
* [`ListView`](docs/components/ListView.md)
|
||||||
|
* [`Portal`](docs/components/Portal.md)
|
||||||
### [`ListView`](docs/components/ListView.md)
|
* [`ScrollView`](docs/components/ScrollView.md)
|
||||||
|
* [`Text`](docs/components/Text.md)
|
||||||
(TODO)
|
* [`TextInput`](docs/components/TextInput.md)
|
||||||
|
* [`TouchableHighlight`](docs/components/TouchableHighlight.md)
|
||||||
### [`ScrollView`](docs/components/ScrollView.md)
|
* [`TouchableOpacity`](docs/components/TouchableOpacity.md)
|
||||||
|
* [`TouchableWithoutFeedback`](docs/components/TouchableWithoutFeedback.md)
|
||||||
A scrollable view with event throttling.
|
* [`View`](docs/components/View.md)
|
||||||
|
* APIs
|
||||||
### [`Text`](docs/components/Text.md)
|
* [`AppRegistry`](docs/apis/AppRegistry.md)
|
||||||
|
* [`AppState`](docs/apis/AppState.md)
|
||||||
Displays text inline and supports basic press handling.
|
* [`AsyncStorage`](docs/apis/AsyncStorage.md)
|
||||||
|
* [`Dimensions`](docs/apis/Dimensions.md)
|
||||||
### [`TextInput`](docs/components/TextInput.md)
|
* [`NativeMethods`](docs/apis/NativeMethods.md)
|
||||||
|
* [`NetInfo`](docs/apis/NetInfo.md)
|
||||||
Accessible single- and multi-line text input via a keyboard.
|
* [`PixelRatio`](docs/apis/PixelRatio.md)
|
||||||
|
* [`Platform`](docs/apis/Platform.md)
|
||||||
### [`Touchable`](docs/components/Touchable.md)
|
* [`StyleSheet`](docs/apis/StyleSheet.md)
|
||||||
|
|
||||||
Touch bindings for press and long press.
|
|
||||||
|
|
||||||
### [`View`](docs/components/View.md)
|
|
||||||
|
|
||||||
The fundamental UI building block using flexbox for layout.
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Please read the [contribution guidelines][contributing-url]. Contributions are
|
|
||||||
welcome!
|
|
||||||
|
|
||||||
## Thanks
|
|
||||||
|
|
||||||
Thanks to current and past members of the React and React Native teams (in
|
|
||||||
particular Vjeux and Pete Hunt).
|
|
||||||
|
|
||||||
Thanks to [react-tappable](https://github.com/JedWatson/react-tappable) for
|
|
||||||
backing the current implementation of `Touchable`.
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (c) 2015 Nicolas Gallagher. Released under the [MIT
|
React Native for Web is [BSD licensed](LICENSE).
|
||||||
license](http://www.opensource.org/licenses/mit-license.php).
|
|
||||||
|
|
||||||
[contributing-url]: https://github.com/necolas/react-native-web/blob/master/CONTRIBUTING.md
|
|
||||||
[discord-url]: http://join.reactiflux.com
|
|
||||||
[flexbox-guide-url]: https://css-tricks.com/snippets/css/a-guide-to-flexbox/
|
|
||||||
[gitter-url]: https://gitter.im/necolas/react-native-web
|
|
||||||
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
[npm-image]: https://badge.fury.io/js/react-native-web.svg
|
||||||
[npm-url]: https://npmjs.org/package/react-native-web
|
[npm-url]: https://npmjs.org/package/react-native-web
|
||||||
[react-native-url]: https://facebook.github.io/react-native/
|
[react-native-url]: https://facebook.github.io/react-native/
|
||||||
|
|||||||
@@ -27,5 +27,10 @@ module.exports = {
|
|||||||
}),
|
}),
|
||||||
new webpack.optimize.DedupePlugin(),
|
new webpack.optimize.DedupePlugin(),
|
||||||
new webpack.optimize.OccurenceOrderPlugin()
|
new webpack.optimize.OccurenceOrderPlugin()
|
||||||
]
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'react-native': '../../src'
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,10 +27,10 @@ Remove a handler by passing the change event `type` and the `handler`.
|
|||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
To see the current state, you can check `AppStateIOS.currentState`, which will
|
To see the current state, you can check `AppState.currentState`, which will be
|
||||||
be kept up-to-date. This example will only ever appear to say "Current state
|
kept up-to-date. This example will only ever appear to say "Current state is:
|
||||||
is: active" because the app is only visible to the user when in the `active`
|
active" because the app is only visible to the user when in the `active` state,
|
||||||
state, and the null state will happen only momentarily.
|
and the null state will happen only momentarily.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
class Example extends React.Component {
|
class Example extends React.Component {
|
||||||
|
|||||||
@@ -9,12 +9,13 @@ The most common and best supported accessibility features of the Web are
|
|||||||
exposed as the props: `accessible`, `accessibilityLabel`,
|
exposed as the props: `accessible`, `accessibilityLabel`,
|
||||||
`accessibilityLiveRegion`, and `accessibilityRole`.
|
`accessibilityLiveRegion`, and `accessibilityRole`.
|
||||||
|
|
||||||
React Native for Web does not provide a way to directly control the rendered
|
React Native for Web does not provide a way to directly control the type of the
|
||||||
HTML element. The `accessibilityRole` prop is used to infer an [analogous HTML
|
rendered HTML element. The `accessibilityRole` prop is used to infer an
|
||||||
element][html-aria-url] to use in addition, where possible. While this may
|
[analogous HTML element][html-aria-url] to use in addition to the resulting
|
||||||
contradict some ARIA recommendations, it also helps avoid certain HTML5
|
ARIA `role`, where possible. While this may contradict some ARIA
|
||||||
conformance errors and accessibility anti-patterns (e.g., giving a `heading`
|
recommendations, it also helps avoid certain HTML5 conformance errors and
|
||||||
role to a `button` element).
|
accessibility anti-patterns (e.g., giving a `heading` role to a `button`
|
||||||
|
element).
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
@@ -24,7 +25,8 @@ For example:
|
|||||||
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
* `<Text accessibilityRole='link' href='/' />` => `<a role='link' href='/' />`.
|
||||||
* `<View accessibilityRole='main' />` => `<main role='main' />`.
|
* `<View accessibilityRole='main' />` => `<main role='main' />`.
|
||||||
|
|
||||||
See the component documentation for more details.
|
Other ARIA properties should be set via [direct
|
||||||
|
manipulation](./direct-manipulation.md).
|
||||||
|
|
||||||
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
|
[aria-in-html-url]: https://w3c.github.io/aria-in-html/
|
||||||
[html-accessibility-url]: http://www.html5accessibility.com/
|
[html-accessibility-url]: http://www.html5accessibility.com/
|
||||||
|
|||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Direct manipulation
|
||||||
|
|
||||||
|
It is sometimes necessary to make changes directly to a component without using
|
||||||
|
state/props to trigger a re-render of the entire subtree – in the browser, this
|
||||||
|
is done by directly modifying a DOM node. `setNativeProps` is the React Native
|
||||||
|
equivalent to setting properties directly on a DOM node. Use direct
|
||||||
|
manipulation when frequent re-rendering creates a performance bottleneck Direct
|
||||||
|
manipulation will not be a tool that you reach for frequently.
|
||||||
|
|
||||||
|
## `setNativeProps` and `shouldComponentUpdate`
|
||||||
|
|
||||||
|
`setNativeProps` is imperative and stores state in the native layer (DOM,
|
||||||
|
UIView, etc.) and not within your React components, which makes your code more
|
||||||
|
difficult to reason about. Before you use it, try to solve your problem with
|
||||||
|
`setState` and `shouldComponentUpdate`.
|
||||||
|
|
||||||
|
## Avoiding conflicts with the render function
|
||||||
|
|
||||||
|
If you update a property that is also managed by the render function, you might
|
||||||
|
end up with some unpredictable and confusing bugs because anytime the component
|
||||||
|
re-renders and that property changes, whatever value was previously set from
|
||||||
|
`setNativeProps` will be completely ignored and overridden.
|
||||||
|
|
||||||
|
## Why use `setNativeProps` on Web?
|
||||||
|
|
||||||
|
Using `setNativeProps` in web-specific code is required when making changes to
|
||||||
|
`className` or `style`, as these properties are controlled by React Native for
|
||||||
|
Web and setting them directly may cause unintended rendering issues.
|
||||||
|
|
||||||
|
```js
|
||||||
|
setOpacityTo(value) {
|
||||||
|
this._childElement.setNativeProps({
|
||||||
|
style: { opacity: value }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Composite components and `setNativeProps`
|
||||||
|
|
||||||
|
Composite components are not backed by a DOM node, so you cannot call
|
||||||
|
`setNativeProps` on them. Consider this example:
|
||||||
|
|
||||||
|
```js
|
||||||
|
const MyButton = (props) => (
|
||||||
|
<View>
|
||||||
|
<Text>{props.label}</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
|
||||||
|
const App = () => (
|
||||||
|
<TouchableOpacity>
|
||||||
|
<MyButton label="Press me!" />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
If you run this you will immediately see this error: `Touchable` child must
|
||||||
|
either be native or forward `setNativeProps` to a native component. This occurs
|
||||||
|
because `MyButton` isn't directly backed by a native view whose opacity should
|
||||||
|
be set. You can think about it like this: if you define a component with
|
||||||
|
`React.Component/createClass` you would not expect to be able to set a style
|
||||||
|
prop on it and have that work - you would need to pass the style prop down to a
|
||||||
|
child, unless you are wrapping a native component. Similarly, we are going to
|
||||||
|
forward `setNativeProps` to a native-backed child component.
|
||||||
|
|
||||||
|
## Forward `setNativeProps` to a child
|
||||||
|
|
||||||
|
All we need to do is provide a `setNativeProps` method on our component that
|
||||||
|
calls `setNativeProps` on the appropriate child with the given arguments.
|
||||||
|
|
||||||
|
```js
|
||||||
|
class MyButton extends React.Component {
|
||||||
|
setNativeProps(nativeProps) {
|
||||||
|
this._root.setNativeProps(nativeProps)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View ref={component => this._root = component}>
|
||||||
|
<Text>{this.props.label}</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
You can now use `MyButton` inside of `TouchableOpacity`!
|
||||||
|
|
||||||
|
## `setNativeProps` to clear `TextInput` value
|
||||||
|
|
||||||
|
Another very common use case of `setNativeProps` is to clear the value of a
|
||||||
|
`TextInput`. For example, the following code demonstrates clearing the input
|
||||||
|
when you tap a button:
|
||||||
|
|
||||||
|
```js
|
||||||
|
class App extends React.Component {
|
||||||
|
_handlePress() {
|
||||||
|
this._textInput.setNativeProps({ text: '' })
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<View style={styles.container}>
|
||||||
|
<TextInput
|
||||||
|
ref={component => this._textInput = component}
|
||||||
|
style={styles.textInput}
|
||||||
|
/>
|
||||||
|
<TouchableOpacity onPress={this._handlePress.bind(this)}>
|
||||||
|
<Text>Clear text</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
# Known issues
|
||||||
|
|
||||||
|
## Missing modules and Views
|
||||||
|
|
||||||
|
This is an initial release of React Native for Web, therefore, not all of the
|
||||||
|
views present on iOS/Android are released on Web. We are very much interested in
|
||||||
|
the community's feedback on the next set of modules and views.
|
||||||
|
|
||||||
|
Not all the modules or views for iOS/Android can be implemented on Web. In some
|
||||||
|
cases it will be necessary to use a Web counterpart.
|
||||||
|
|
||||||
|
## Missing component props
|
||||||
|
|
||||||
|
There are properties that do not work across all platforms. All web-specific
|
||||||
|
props are annotated with `(web)` in the documentaiton.
|
||||||
|
|
||||||
|
## Platform parity
|
||||||
|
|
||||||
|
There are some known issues in React Native where APIs could be made more
|
||||||
|
consistent between platforms. For example, React Native for Web includes
|
||||||
|
`ActivityIndicator` and a horizontal `ProgressBar`.
|
||||||
|
|
||||||
|
Other parts of React Native, such as the `Animated` and `PanResponder` APIs,
|
||||||
|
are highly complex and have not yet been ported to React Native for Web. Given
|
||||||
|
the difficulties keeping these APIs in sync with React Native, we'd prefer the
|
||||||
|
APIs to be published as separate npm packages. If not, we will consider a web
|
||||||
|
implementation, possibly using the [Web Animations
|
||||||
|
API/polyfill](https://github.com/web-animations/web-animations-js)
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
# React Native
|
||||||
|
|
||||||
|
This is an experimental feature to support: using community-developed React
|
||||||
|
Native components on the Web; and rendering React Native apps to Web.
|
||||||
|
|
||||||
|
Use a module loader that supports package aliases (e.g., webpack), and alias
|
||||||
|
`react-native` to `react-native-web`.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// webpack.config.js
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'react-native': 'react-native-web'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Web-specific implementations can use the `*.web.js` naming pattern, which
|
||||||
|
webpack will resolve.
|
||||||
|
|
||||||
|
Minor platform differences can use the `Platform` module.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { AppRegistry, Platform, StyleSheet } from 'react-native'
|
||||||
|
|
||||||
|
const styles = StyleSheet.create({
|
||||||
|
height: (Platform.OS === 'web') ? 200 : 100
|
||||||
|
})
|
||||||
|
|
||||||
|
AppRegistry.registerComponent('MyApp', () => MyApp)
|
||||||
|
|
||||||
|
if (Platform.OS === 'web') {
|
||||||
|
AppRegistry.runApplication('MyApp', {
|
||||||
|
rootTag: document.getElementById('react-root')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
# Client and Server rendering
|
||||||
|
|
||||||
|
## Client-side rendering
|
||||||
|
|
||||||
|
```js
|
||||||
|
// client.js
|
||||||
|
|
||||||
|
import React, { AppRegistry } from 'react-native'
|
||||||
|
import MyApp from './MyApp'
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerApp('MyApp', () => MyApp)
|
||||||
|
|
||||||
|
// mount the app within the `rootTag` and run it
|
||||||
|
AppRegistry.runApplication('MyApp', { initialProps, rootTag: document.getElementById('react-root') })
|
||||||
|
|
||||||
|
// DOM render
|
||||||
|
React.render(<div />, document.getElementById('sidebar-app'))
|
||||||
|
|
||||||
|
// Server render
|
||||||
|
React.renderToString(<div />)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Server-side rendering
|
||||||
|
|
||||||
|
Pre-rendering React apps on the server is a key feature for Web applications.
|
||||||
|
React Native for Web extends `AppRegistry` to provide support for server-side
|
||||||
|
rendering.
|
||||||
|
|
||||||
|
```js
|
||||||
|
// server.js
|
||||||
|
|
||||||
|
import React, { AppRegistry } from 'react-native'
|
||||||
|
import MyApp from './MyApp'
|
||||||
|
|
||||||
|
// register the app
|
||||||
|
AppRegistry.registerApp('MyApp', () => MyApp)
|
||||||
|
|
||||||
|
// prerender the app
|
||||||
|
const { html, style } = AppRegistry.prerenderApplication('MyApp', { initialProps })
|
||||||
|
|
||||||
|
// construct full page markup
|
||||||
|
const HtmlShell = (html, style) => (
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charSet="utf-8" />
|
||||||
|
<meta content="initial-scale=1,width=device-width" name="viewport" />
|
||||||
|
{style}
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="react-root" dangerouslySetInnerHTML={{ __html: html }} />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
)
|
||||||
|
|
||||||
|
React.renderToStaticMarkup(<HtmlShell html={html} style={style} />)
|
||||||
|
```
|
||||||
+21
-16
@@ -42,7 +42,7 @@ documentation of individual components.
|
|||||||
|
|
||||||
## Using styles
|
## Using styles
|
||||||
|
|
||||||
All the core components accept a `style` attribute.
|
All the React Native components accept a `style` attribute.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
<Text style={styles.text} />
|
<Text style={styles.text} />
|
||||||
@@ -52,20 +52,27 @@ All the core components accept a `style` attribute.
|
|||||||
A common pattern is to conditionally add style based on a condition:
|
A common pattern is to conditionally add style based on a condition:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
// either
|
||||||
<View style={{
|
<View style={{
|
||||||
...styles.base,
|
...styles.base,
|
||||||
...(this.state.active && styles.active)
|
...(this.state.active && styles.active)
|
||||||
}} />
|
}} />
|
||||||
|
|
||||||
|
// or
|
||||||
|
<View style={[
|
||||||
|
styles.base,
|
||||||
|
this.state.active && styles.active
|
||||||
|
]} />
|
||||||
```
|
```
|
||||||
|
|
||||||
## Composing styles
|
## Composing styles
|
||||||
|
|
||||||
In order to let a call site customize the style of your component children, you
|
In order to let a call site customize the style of your component children, you
|
||||||
can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in
|
can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in
|
||||||
order to make sure only styles are being passed.
|
order to make sure only valid styles are being passed.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export default class List extends React.Component {
|
class List extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
style: View.propTypes.style,
|
style: View.propTypes.style,
|
||||||
elementStyle: View.propTypes.style,
|
elementStyle: View.propTypes.style,
|
||||||
@@ -108,11 +115,11 @@ class List extends React.Component {
|
|||||||
return (
|
return (
|
||||||
<View
|
<View
|
||||||
children={children}
|
children={children}
|
||||||
style={{
|
style={[
|
||||||
...this.props.style,
|
this.props.style,
|
||||||
// override border-color when scrolling
|
// override border-color when scrolling
|
||||||
...(isScrolling && { borderColor: 'transparent' })
|
isScrolling && { borderColor: 'transparent' }
|
||||||
}}
|
]}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -125,19 +132,17 @@ class List extends React.Component {
|
|||||||
it does not concern itself with _where_ or _when_ those styles are applied to
|
it does not concern itself with _where_ or _when_ those styles are applied to
|
||||||
elements.
|
elements.
|
||||||
|
|
||||||
Changing styles in response to device adaptation can be controlled using
|
There are various React libraries wrapping JavaScript Media Query API's, e.g.,
|
||||||
JavaScript Media Query API's. There are several React libraries that provide a
|
|
||||||
means to do this, e.g.,
|
|
||||||
[react-media-queries](https://github.com/bloodyowl/react-media-queries),
|
[react-media-queries](https://github.com/bloodyowl/react-media-queries),
|
||||||
[media-query-fascade](https://github.com/tanem/media-query-facade), or
|
[media-query-fascade](https://github.com/tanem/media-query-facade), or
|
||||||
[react-responsive](https://github.com/contra/react-responsive). This approach
|
[react-responsive](https://github.com/contra/react-responsive). This has the
|
||||||
has the benefit of co-locating breakpoint-specific DOM and style changes.
|
benefit of co-locating breakpoint-specific DOM and style changes.
|
||||||
|
|
||||||
## Pseudo-classes and pseudo-elements
|
## Pseudo-classes and pseudo-elements
|
||||||
|
|
||||||
Pseudo-classes like `:hover` and `:focus` can be implemented with the `onHover`
|
Pseudo-classes like `:hover` and `:focus` can be implemented with the events
|
||||||
and `onFocus` events. Pseudo-elements are not supported; elements should be
|
(e.g. `onFocus`). Pseudo-elements are not supported; elements should be used
|
||||||
used instead.
|
instead.
|
||||||
|
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
@@ -149,7 +154,7 @@ corresponding `className`'s.
|
|||||||
By doing this, the total size of the generated CSS is determined by the
|
By doing this, the total size of the generated CSS is determined by the
|
||||||
total number of unique declarations (rather than the total number of rules in
|
total number of unique declarations (rather than the total number of rules in
|
||||||
the application), making it viable to inline the style sheet when pre-rendering
|
the application), making it viable to inline the style sheet when pre-rendering
|
||||||
on the server.
|
on the server. Styles are updated if new module bundle are loaded asynchronously.
|
||||||
|
|
||||||
JavaScript definition:
|
JavaScript definition:
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import GridView from './GridView'
|
import GridView from './GridView'
|
||||||
import Heading from './Heading'
|
import Heading from './Heading'
|
||||||
import MediaQueryWidget from './MediaQueryWidget'
|
import MediaQueryWidget from './MediaQueryWidget'
|
||||||
import React, { Image, StyleSheet, ScrollView, Text, TextInput, Touchable, View } from '../../src'
|
import React, { Image, StyleSheet, ScrollView, Text, TextInput, TouchableHighlight, View } from 'react-native'
|
||||||
|
|
||||||
export default class App extends React.Component {
|
export default class App extends React.Component {
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
@@ -25,7 +25,8 @@ export default class App extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<View accessibilityRole='main' style={rootStyles}>
|
<ScrollView accessibilityRole='main'>
|
||||||
|
<View style={rootStyles}>
|
||||||
<Heading size='xlarge'>React Native for Web</Heading>
|
<Heading size='xlarge'>React Native for Web</Heading>
|
||||||
<Text>React Native Web takes the core components from <Text
|
<Text>React Native Web takes the core components from <Text
|
||||||
accessibilityRole='link' href='https://facebook.github.io/react-native/'>React
|
accessibilityRole='link' href='https://facebook.github.io/react-native/'>React
|
||||||
@@ -107,7 +108,7 @@ export default class App extends React.Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Heading size='large'>Touchable</Heading>
|
<Heading size='large'>Touchable</Heading>
|
||||||
<Touchable
|
<TouchableHighlight
|
||||||
accessibilityLabel={'Touchable element'}
|
accessibilityLabel={'Touchable element'}
|
||||||
activeHighlight='lightblue'
|
activeHighlight='lightblue'
|
||||||
activeOpacity={0.8}
|
activeOpacity={0.8}
|
||||||
@@ -119,7 +120,7 @@ export default class App extends React.Component {
|
|||||||
<View style={styles.touchableArea}>
|
<View style={styles.touchableArea}>
|
||||||
<Text>Touchable area (press, long press)</Text>
|
<Text>Touchable area (press, long press)</Text>
|
||||||
</View>
|
</View>
|
||||||
</Touchable>
|
</TouchableHighlight>
|
||||||
|
|
||||||
<Heading size='large'>View</Heading>
|
<Heading size='large'>View</Heading>
|
||||||
<Heading>Default layout</Heading>
|
<Heading>Default layout</Heading>
|
||||||
@@ -205,7 +206,8 @@ export default class App extends React.Component {
|
|||||||
))}
|
))}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
</ScrollView>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-5
@@ -2,7 +2,7 @@ import { MediaProvider, matchMedia } from 'react-media-queries'
|
|||||||
import App from './components/App'
|
import App from './components/App'
|
||||||
import createGetter from 'react-media-queries/lib/createMediaQueryGetter'
|
import createGetter from 'react-media-queries/lib/createMediaQueryGetter'
|
||||||
import createListener from 'react-media-queries/lib/createMediaQueryListener'
|
import createListener from 'react-media-queries/lib/createMediaQueryListener'
|
||||||
import React from '../src'
|
import React, { AppRegistry } from '../src'
|
||||||
|
|
||||||
const mediaQueries = {
|
const mediaQueries = {
|
||||||
small: '(min-width: 300px)',
|
small: '(min-width: 300px)',
|
||||||
@@ -10,10 +10,14 @@ const mediaQueries = {
|
|||||||
large: '(min-width: 500px)'
|
large: '(min-width: 500px)'
|
||||||
}
|
}
|
||||||
const ResponsiveApp = matchMedia()(App)
|
const ResponsiveApp = matchMedia()(App)
|
||||||
|
const WrappedApp = () => (
|
||||||
React.render(
|
|
||||||
<MediaProvider getMedia={createGetter(mediaQueries)} listener={createListener(mediaQueries)}>
|
<MediaProvider getMedia={createGetter(mediaQueries)} listener={createListener(mediaQueries)}>
|
||||||
<ResponsiveApp />
|
<ResponsiveApp />
|
||||||
</MediaProvider>,
|
</MediaProvider>
|
||||||
document.getElementById('react-root')
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
AppRegistry.registerComponent('Example', () => WrappedApp)
|
||||||
|
|
||||||
|
AppRegistry.runApplication('Example', {
|
||||||
|
rootTag: document.getElementById('react-root')
|
||||||
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user