diff --git a/docs/Animations.md b/docs/Animations.md index c97fe2b460b077..dfcf64ccecc9e1 100644 --- a/docs/Animations.md +++ b/docs/Animations.md @@ -26,34 +26,33 @@ The [`Animated`](docs/animated.html) API is designed to make it very easy to con For example, a container view that fades in when it is mounted may look like this: -```javascript -// FadeInView.js -import React, { Component } from 'react'; -import { - Animated, -} from 'react-native'; +```SnackPlayer +import React from 'react'; +import { Animated, Text, View } from 'react-native'; -class FadeInView extends Component { - constructor(props) { - super(props); - this.state = { - fadeAnim: new Animated.Value(0), // Initial value for opacity: 0 - }; +class FadeInView extends React.Component { + state = { + fadeAnim: new Animated.Value(0), // Initial value for opacity: 0 } + componentDidMount() { - Animated.timing( // Animate over time - this.state.fadeAnim, // The animated value to drive + Animated.timing( // Animate over time + this.state.fadeAnim, // The animated value to drive { - toValue: 1, // Animate to opacity: 1, or fully opaque + toValue: 1, // Animate to opacity: 1 (opaque) + duration: 10000, // Make it take a while } - ).start(); // Starts the animation + ).start(); // Starts the animation } + render() { + let { fadeAnim } = this.state; + return ( - {this.props.children} @@ -62,23 +61,20 @@ class FadeInView extends Component { } } -module.exports = FadeInView; -``` - -You can then use your `FadeInView` in place of a `View` in your components, like so: - -```javascript -render() { - return ( - - Fading in - - ) +// You can then use your `FadeInView` in place of a `View` in your components: +export default class App extends React.Component { + render() { + return ( + + + Fading in + + + ) + } } ``` -![FadeInView](img/AnimatedFadeInView.gif) - Let's break down what's happening here. In the `FadeInView` constructor, a new `Animated.Value` called `fadeAnim` is initialized as part of `state`. The opacity property on the `View` is mapped to this animated value. @@ -393,22 +389,29 @@ Note that in order to get this to work on **Android** you need to set the follow UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true); ``` -![](img/LayoutAnimationExample.gif) +```SnackPlayer +import React from 'react'; +import { + NativeModules, + LayoutAnimation, + Text, + TouchableOpacity, + StyleSheet, + View, +} from 'react-native'; + +const { UIManager } = NativeModules; -```javascript -class App extends React.Component { - constructor(props) { - super(props); - this.state = { w: 100, h: 100 }; - this._onPress = this._onPress.bind(this); - } +UIManager.setLayoutAnimationEnabledExperimental && + UIManager.setLayoutAnimationEnabledExperimental(true); - componentWillMount() { - // Animate creation - LayoutAnimation.spring(); - } +export default class App extends React.Component { + state = { + w: 100, + h: 100, + }; - _onPress() { + _onPress = () => { // Animate the update LayoutAnimation.spring(); this.setState({w: this.state.w + 15, h: this.state.h + 15}) @@ -427,8 +430,30 @@ class App extends React.Component { ); } } + +const styles = StyleSheet.create({ + container: { + flex: 1, + alignItems: 'center', + justifyContent: 'center', + }, + box: { + width: 200, + height: 200, + backgroundColor: 'red', + }, + button: { + backgroundColor: 'black', + paddingHorizontal: 20, + paddingVertical: 15, + marginTop: 15, + }, + buttonText: { + color: '#fff', + fontWeight: 'bold', + }, +}); ``` -[Run this example](https://rnplay.org/apps/uaQrGQ) This example uses a preset value, you can customize the animations as you need, see [LayoutAnimation.js](https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js) @@ -457,45 +482,12 @@ We could use this in the Rebound example to update the scale - this might be helpful if the component that we are updating is deeply nested and hasn't been optimized with `shouldComponentUpdate`. -```javascript -// Back inside of the App component, replace the scrollSpring listener -// in componentWillMount with this: -this._scrollSpring.addListener({ - onSpringUpdate: () => { - if (!this._photo) { return } - var v = this._scrollSpring.getCurrentValue(); - var newProps = {style: {transform: [{scaleX: v}, {scaleY: v}]}}; - this._photo.setNativeProps(newProps); - }, -}); - -// Lastly, we update the render function to no longer pass in the -// transform via style (avoid clashes when re-rendering) and to set the -// photo ref -render() { - return ( - - - this._photo = component} - source={{uri: "img/ReboundExample.png"}} - style={{width: 250, height: 200}} /> - - - ); -} -``` -[Run this example](https://rnplay.org/apps/fUqjAg) - -It would not make sense to use `setNativeProps` with react-tween-state -because the updated tween values are set on the state automatically by -the library - Rebound on the other hand gives us an updated value for -each frame with the `onSpringUpdate` function. - -If you find your animations with dropping frames (performing below 60 -frames per second), look into using `setNativeProps` or -`shouldComponentUpdate` to optimize them. You may also want to defer any -computationally intensive work until after animations are complete, -using the -[InteractionManager](docs/interactionmanager.html). You -can monitor the frame rate by using the In-App Developer Menu "FPS -Monitor" tool. +If you find your animations with dropping frames (performing below 60 frames +per second), look into using `setNativeProps` or `shouldComponentUpdate` to +optimize them. Or you could run the animations on the UI thread rather than +the JavaScript thread [with the useNativeDriver +option](http://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html). +You may also want to defer any computationally intensive work until after +animations are complete, using the +[InteractionManager](docs/interactionmanager.html). You can monitor the +frame rate by using the In-App Developer Menu "FPS Monitor" tool. \ No newline at end of file diff --git a/docs/DirectManipulation.md b/docs/DirectManipulation.md index 8c692544d5791e..ae0924cde9f388 100644 --- a/docs/DirectManipulation.md +++ b/docs/DirectManipulation.md @@ -94,7 +94,10 @@ ReactNativeBaseComponent.js](https://github.com/facebook/react/blob/master/src/r Composite components are not backed by a native view, so you cannot call `setNativeProps` on them. Consider this example: -```javascript +```SnackPlayer?name=setNativeProps%20with%20Composite%20Components +import React from 'react'; +import { Text, TouchableOpacity, View } from 'react-native'; + class MyButton extends React.Component { render() { return ( @@ -105,7 +108,7 @@ class MyButton extends React.Component { } } -class App extends React.Component { +export default class App extends React.Component { render() { return ( @@ -115,7 +118,6 @@ class App extends React.Component { } } ``` -[Run this example](https://rnplay.org/apps/JXkgmQ) If you run this you will immediately see this error: `Touchable child must either be native or forward setNativeProps to a native component`. @@ -133,9 +135,12 @@ All we need to do is provide a `setNativeProps` method on our component that calls `setNativeProps` on the appropriate child with the given arguments. -```javascript +```SnackPlayer?name=Forwarding%20setNativeProps +import React from 'react'; +import { Text, TouchableOpacity, View } from 'react-native'; + class MyButton extends React.Component { - setNativeProps(nativeProps) { + setNativeProps = (nativeProps) => { this._root.setNativeProps(nativeProps); } @@ -147,8 +152,17 @@ class MyButton extends React.Component { ) } } + +export default class App extends React.Component { + render() { + return ( + + + + ) + } +} ``` -[Run this example](https://rnplay.org/apps/YJxnEQ) You can now use `MyButton` inside of `TouchableOpacity`! A sidenote for clarity: we used the [ref callback](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute) syntax here, rather than the traditional string-based ref. @@ -173,22 +187,22 @@ use `setNativeProps` to directly manipulate the TextInput value when necessary. For example, the following code demonstrates clearing the input when you tap a button: -```javascript -class App extends React.Component { - constructor(props) { - super(props); - this.clearText = this.clearText.bind(this); - } +```SnackPlayer?name=Clear%20text +import React from 'react'; +import { TextInput, Text, TouchableOpacity, View } from 'react-native'; - clearText() { +export default class App extends React.Component { + clearText = () => { this._textInput.setNativeProps({text: ''}); } render() { return ( - - this._textInput = component} - style={styles.textInput} /> + + this._textInput = component} + style={{height: 50, flex: 1, marginHorizontal: 20, borderWidth: 1, borderColor: '#ccc'}} + /> Clear text @@ -197,7 +211,6 @@ class App extends React.Component { } } ``` -[Run this example](https://rnplay.org/plays/pOI9bA) ## Avoiding conflicts with the render function @@ -205,9 +218,7 @@ 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. [See this example](https://rnplay.org/apps/bp1DvQ) -for a demonstration of what can happen if these two collide - notice -the jerky animation each 250ms when `setState` triggers a re-render. +ignored and overridden. ## setNativeProps & shouldComponentUpdate diff --git a/website/core/Marked.js b/website/core/Marked.js index f727315cc06e08..64bc26feba7408 100644 --- a/website/core/Marked.js +++ b/website/core/Marked.js @@ -15,6 +15,7 @@ var Header = require('Header'); var Prism = require('Prism'); var React = require('React'); var WebPlayer = require('WebPlayer'); +var SnackPlayer = require('SnackPlayer'); /** * Block-Level Grammar @@ -842,6 +843,12 @@ Parser.prototype.tok = function() { ); } + if (lang && lang.indexOf('SnackPlayer') === 0) { + return ( + {text} + ); + } + return {text}; } case 'table': { diff --git a/website/core/Site.js b/website/core/Site.js index 736b8a7170c2d2..286aa06b05d2c0 100644 --- a/website/core/Site.js +++ b/website/core/Site.js @@ -20,9 +20,11 @@ var Site = React.createClass({ const version = Metadata.config.RN_VERSION; const algoliaVersion = version === 'next' ? 'master' : version; var basePath = '/react-native/' + (path ? path + '/' : ''); - var currentYear = (new Date()).getFullYear(); + var currentYear = new Date().getFullYear(); - var title = this.props.title ? this.props.title : 'React Native | A framework for building native apps using React'; + var title = this.props.title + ? this.props.title + : 'React Native | A framework for building native apps using React'; var metaTags = [ { charSet: 'utf-8' }, @@ -35,8 +37,8 @@ var Site = React.createClass({ content: 'width=device-width', }, // Facebook - { property: 'fb:app_id', content: '1677033832619985', }, - { property: 'fb:admins', content: '121800083', }, + { property: 'fb:app_id', content: '1677033832619985' }, + { property: 'fb:admins', content: '121800083' }, // Open Graph { property: 'og:site_name', @@ -48,15 +50,20 @@ var Site = React.createClass({ }, { property: 'og:url', - content: 'https://facebook.github.io/react-native/' + (this.props.path ? this.props.path : 'index.html'), + content: 'https://facebook.github.io/react-native/' + + (this.props.path ? this.props.path : 'index.html'), }, { property: 'og:image', - content: this.props.image ? this.props.image : 'https://facebook.github.io/react-native/img/opengraph.png', + content: this.props.image + ? this.props.image + : 'https://facebook.github.io/react-native/img/opengraph.png', }, { property: 'og:description', - content: this.props.description ? this.props.description : 'A framework for building native apps using React', + content: this.props.description + ? this.props.description + : 'A framework for building native apps using React', }, // Twitter Cards { @@ -69,18 +76,23 @@ var Site = React.createClass({ }, ]; - var typeTags = [{ - property: 'og:type', - content: 'website', - }]; - if (this.props.author) { - typeTags = [{ + var typeTags = [ + { property: 'og:type', - content: 'article', - }, { - property: 'article:author', - content: this.props.author, - }]; + content: 'website', + }, + ]; + if (this.props.author) { + typeTags = [ + { + property: 'og:type', + content: 'article', + }, + { + property: 'article:author', + content: this.props.author, + }, + ]; } metaTags.push(...typeTags); @@ -95,27 +107,46 @@ var Site = React.createClass({ {title} - { - metaTags.map((tag, index) => - ) - } + {metaTags.map((tag, index) => )} - + - - + + + -