Move away from rnplay to snack, with embedded examples!

Summary:
React Native Playground has been sunset, so I've replaced the examples that previously used it with examples using [Snack](http://snack.expo.io/).

The examples are directly embedded and can be edited live to see updates. The code itself is also in the docs, so we can easily update the docs in one place and we don't have to actually go to a saved app on Snack and update it there.

Run it locally, go to the `Animations` section and the `Direct Manipulation` section.

![screen shot 2017-04-03 at 6 29 51 pm](https://cloud.githubusercontent.com/assets/90494/24638271/ff3ad044-189b-11e7-845d-24b2fb612d95.png)

Open it on your phone, notice that it falls back to just showing plain code.

<img src="https://cloud.githubusercontent.com/assets/90494/24638547/203ec8fc-189e-11e7-99c8-dfabff949f8d.PNG" width="250">

- Get rid of the Expo new user experience dialog that you see when you open a Snack -- is this a dealbreaker
Closes https://github.com/facebook/react-native/pull/13285

Differential Revision: D4828011

Pulled By: hramos

fbshipit-source-id: 684ad24a14deb72abb8587ffbb726d316f126d75
This commit is contained in:
Brent Vatne
2017-04-05 18:55:45 -07:00
committed by Facebook Github Bot
parent 6dbcb47e4c
commit b8542397cd
6 changed files with 439 additions and 169 deletions

View File

@@ -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 (
<Animated.View // Special animatable View
<Animated.View // Special animatable View
style={{
...this.props.style,
opacity: this.state.fadeAnim, // Bind opacity to animated value
opacity: fadeAnim, // Bind opacity to animated value
}}
>
{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 (
<FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
</FadeInView>
)
// You can then use your `FadeInView` in place of a `View` in your components:
export default class App extends React.Component {
render() {
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
</FadeInView>
</View>
)
}
}
```
![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';
```javascript
class App extends React.Component {
constructor(props) {
super(props);
this.state = { w: 100, h: 100 };
this._onPress = this._onPress.bind(this);
}
const { UIManager } = NativeModules;
componentWillMount() {
// Animate creation
LayoutAnimation.spring();
}
UIManager.setLayoutAnimationEnabledExperimental &&
UIManager.setLayoutAnimationEnabledExperimental(true);
_onPress() {
export default class App extends React.Component {
state = {
w: 100,
h: 100,
};
_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 (
<View style={styles.container}>
<TouchableWithoutFeedback onPressIn={this._onPressIn} onPressOut={this._onPressOut}>
<Image ref={component => this._photo = component}
source={{uri: "img/ReboundExample.png"}}
style={{width: 250, height: 200}} />
</TouchableWithoutFeedback>
</View>
);
}
```
[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.