Skip to content

Commit b854239

Browse files
brentvatnefacebook-github-bot
authored andcommitted
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 #13285 Differential Revision: D4828011 Pulled By: hramos fbshipit-source-id: 684ad24a14deb72abb8587ffbb726d316f126d75
1 parent 6dbcb47 commit b854239

File tree

6 files changed

+439
-169
lines changed

6 files changed

+439
-169
lines changed

docs/Animations.md

Lines changed: 80 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,33 @@ The [`Animated`](docs/animated.html) API is designed to make it very easy to con
2626

2727
For example, a container view that fades in when it is mounted may look like this:
2828

29-
```javascript
30-
// FadeInView.js
31-
import React, { Component } from 'react';
32-
import {
33-
Animated,
34-
} from 'react-native';
29+
```SnackPlayer
30+
import React from 'react';
31+
import { Animated, Text, View } from 'react-native';
3532
36-
class FadeInView extends Component {
37-
constructor(props) {
38-
super(props);
39-
this.state = {
40-
fadeAnim: new Animated.Value(0), // Initial value for opacity: 0
41-
};
33+
class FadeInView extends React.Component {
34+
state = {
35+
fadeAnim: new Animated.Value(0), // Initial value for opacity: 0
4236
}
37+
4338
componentDidMount() {
44-
Animated.timing( // Animate over time
45-
this.state.fadeAnim, // The animated value to drive
39+
Animated.timing( // Animate over time
40+
this.state.fadeAnim, // The animated value to drive
4641
{
47-
toValue: 1, // Animate to opacity: 1, or fully opaque
42+
toValue: 1, // Animate to opacity: 1 (opaque)
43+
duration: 10000, // Make it take a while
4844
}
49-
).start(); // Starts the animation
45+
).start(); // Starts the animation
5046
}
47+
5148
render() {
49+
let { fadeAnim } = this.state;
50+
5251
return (
53-
<Animated.View // Special animatable View
52+
<Animated.View // Special animatable View
5453
style={{
5554
...this.props.style,
56-
opacity: this.state.fadeAnim, // Bind opacity to animated value
55+
opacity: fadeAnim, // Bind opacity to animated value
5756
}}
5857
>
5958
{this.props.children}
@@ -62,23 +61,20 @@ class FadeInView extends Component {
6261
}
6362
}
6463
65-
module.exports = FadeInView;
66-
```
67-
68-
You can then use your `FadeInView` in place of a `View` in your components, like so:
69-
70-
```javascript
71-
render() {
72-
return (
73-
<FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
74-
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
75-
</FadeInView>
76-
)
64+
// You can then use your `FadeInView` in place of a `View` in your components:
65+
export default class App extends React.Component {
66+
render() {
67+
return (
68+
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
69+
<FadeInView style={{width: 250, height: 50, backgroundColor: 'powderblue'}}>
70+
<Text style={{fontSize: 28, textAlign: 'center', margin: 10}}>Fading in</Text>
71+
</FadeInView>
72+
</View>
73+
)
74+
}
7775
}
7876
```
7977

80-
![FadeInView](img/AnimatedFadeInView.gif)
81-
8278
Let's break down what's happening here.
8379
In the `FadeInView` constructor, a new `Animated.Value` called `fadeAnim` is initialized as part of `state`.
8480
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
393389
UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true);
394390
```
395391

396-
![](img/LayoutAnimationExample.gif)
392+
```SnackPlayer
393+
import React from 'react';
394+
import {
395+
NativeModules,
396+
LayoutAnimation,
397+
Text,
398+
TouchableOpacity,
399+
StyleSheet,
400+
View,
401+
} from 'react-native';
402+
403+
const { UIManager } = NativeModules;
397404
398-
```javascript
399-
class App extends React.Component {
400-
constructor(props) {
401-
super(props);
402-
this.state = { w: 100, h: 100 };
403-
this._onPress = this._onPress.bind(this);
404-
}
405+
UIManager.setLayoutAnimationEnabledExperimental &&
406+
UIManager.setLayoutAnimationEnabledExperimental(true);
405407
406-
componentWillMount() {
407-
// Animate creation
408-
LayoutAnimation.spring();
409-
}
408+
export default class App extends React.Component {
409+
state = {
410+
w: 100,
411+
h: 100,
412+
};
410413
411-
_onPress() {
414+
_onPress = () => {
412415
// Animate the update
413416
LayoutAnimation.spring();
414417
this.setState({w: this.state.w + 15, h: this.state.h + 15})
@@ -427,8 +430,30 @@ class App extends React.Component {
427430
);
428431
}
429432
}
433+
434+
const styles = StyleSheet.create({
435+
container: {
436+
flex: 1,
437+
alignItems: 'center',
438+
justifyContent: 'center',
439+
},
440+
box: {
441+
width: 200,
442+
height: 200,
443+
backgroundColor: 'red',
444+
},
445+
button: {
446+
backgroundColor: 'black',
447+
paddingHorizontal: 20,
448+
paddingVertical: 15,
449+
marginTop: 15,
450+
},
451+
buttonText: {
452+
color: '#fff',
453+
fontWeight: 'bold',
454+
},
455+
});
430456
```
431-
[Run this example](https://rnplay.org/apps/uaQrGQ)
432457

433458
This example uses a preset value, you can customize the animations as
434459
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
457482
might be helpful if the component that we are updating is deeply nested
458483
and hasn't been optimized with `shouldComponentUpdate`.
459484

460-
```javascript
461-
// Back inside of the App component, replace the scrollSpring listener
462-
// in componentWillMount with this:
463-
this._scrollSpring.addListener({
464-
onSpringUpdate: () => {
465-
if (!this._photo) { return }
466-
var v = this._scrollSpring.getCurrentValue();
467-
var newProps = {style: {transform: [{scaleX: v}, {scaleY: v}]}};
468-
this._photo.setNativeProps(newProps);
469-
},
470-
});
471-
472-
// Lastly, we update the render function to no longer pass in the
473-
// transform via style (avoid clashes when re-rendering) and to set the
474-
// photo ref
475-
render() {
476-
return (
477-
<View style={styles.container}>
478-
<TouchableWithoutFeedback onPressIn={this._onPressIn} onPressOut={this._onPressOut}>
479-
<Image ref={component => this._photo = component}
480-
source={{uri: "img/ReboundExample.png"}}
481-
style={{width: 250, height: 200}} />
482-
</TouchableWithoutFeedback>
483-
</View>
484-
);
485-
}
486-
```
487-
[Run this example](https://rnplay.org/apps/fUqjAg)
488-
489-
It would not make sense to use `setNativeProps` with react-tween-state
490-
because the updated tween values are set on the state automatically by
491-
the library - Rebound on the other hand gives us an updated value for
492-
each frame with the `onSpringUpdate` function.
493-
494-
If you find your animations with dropping frames (performing below 60
495-
frames per second), look into using `setNativeProps` or
496-
`shouldComponentUpdate` to optimize them. You may also want to defer any
497-
computationally intensive work until after animations are complete,
498-
using the
499-
[InteractionManager](docs/interactionmanager.html). You
500-
can monitor the frame rate by using the In-App Developer Menu "FPS
501-
Monitor" tool.
485+
If you find your animations with dropping frames (performing below 60 frames
486+
per second), look into using `setNativeProps` or `shouldComponentUpdate` to
487+
optimize them. Or you could run the animations on the UI thread rather than
488+
the JavaScript thread [with the useNativeDriver
489+
option](http://facebook.github.io/react-native/blog/2017/02/14/using-native-driver-for-animated.html).
490+
You may also want to defer any computationally intensive work until after
491+
animations are complete, using the
492+
[InteractionManager](docs/interactionmanager.html). You can monitor the
493+
frame rate by using the In-App Developer Menu "FPS Monitor" tool.

docs/DirectManipulation.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ ReactNativeBaseComponent.js](https://github.com/facebook/react/blob/master/src/r
9494
Composite components are not backed by a native view, so you cannot call
9595
`setNativeProps` on them. Consider this example:
9696

97-
```javascript
97+
```SnackPlayer?name=setNativeProps%20with%20Composite%20Components
98+
import React from 'react';
99+
import { Text, TouchableOpacity, View } from 'react-native';
100+
98101
class MyButton extends React.Component {
99102
render() {
100103
return (
@@ -105,7 +108,7 @@ class MyButton extends React.Component {
105108
}
106109
}
107110
108-
class App extends React.Component {
111+
export default class App extends React.Component {
109112
render() {
110113
return (
111114
<TouchableOpacity>
@@ -115,7 +118,6 @@ class App extends React.Component {
115118
}
116119
}
117120
```
118-
[Run this example](https://rnplay.org/apps/JXkgmQ)
119121

120122
If you run this you will immediately see this error: `Touchable child
121123
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
133135
that calls `setNativeProps` on the appropriate child with the given
134136
arguments.
135137

136-
```javascript
138+
```SnackPlayer?name=Forwarding%20setNativeProps
139+
import React from 'react';
140+
import { Text, TouchableOpacity, View } from 'react-native';
141+
137142
class MyButton extends React.Component {
138-
setNativeProps(nativeProps) {
143+
setNativeProps = (nativeProps) => {
139144
this._root.setNativeProps(nativeProps);
140145
}
141146
@@ -147,8 +152,17 @@ class MyButton extends React.Component {
147152
)
148153
}
149154
}
155+
156+
export default class App extends React.Component {
157+
render() {
158+
return (
159+
<TouchableOpacity>
160+
<MyButton label="Press me!" />
161+
</TouchableOpacity>
162+
)
163+
}
164+
}
150165
```
151-
[Run this example](https://rnplay.org/apps/YJxnEQ)
152166

153167
You can now use `MyButton` inside of `TouchableOpacity`! A sidenote for
154168
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
173187
necessary. For example, the following code demonstrates clearing the
174188
input when you tap a button:
175189

176-
```javascript
177-
class App extends React.Component {
178-
constructor(props) {
179-
super(props);
180-
this.clearText = this.clearText.bind(this);
181-
}
190+
```SnackPlayer?name=Clear%20text
191+
import React from 'react';
192+
import { TextInput, Text, TouchableOpacity, View } from 'react-native';
182193
183-
clearText() {
194+
export default class App extends React.Component {
195+
clearText = () => {
184196
this._textInput.setNativeProps({text: ''});
185197
}
186198
187199
render() {
188200
return (
189-
<View style={styles.container}>
190-
<TextInput ref={component => this._textInput = component}
191-
style={styles.textInput} />
201+
<View style={{flex: 1}}>
202+
<TextInput
203+
ref={component => this._textInput = component}
204+
style={{height: 50, flex: 1, marginHorizontal: 20, borderWidth: 1, borderColor: '#ccc'}}
205+
/>
192206
<TouchableOpacity onPress={this.clearText}>
193207
<Text>Clear text</Text>
194208
</TouchableOpacity>
@@ -197,17 +211,14 @@ class App extends React.Component {
197211
}
198212
}
199213
```
200-
[Run this example](https://rnplay.org/plays/pOI9bA)
201214

202215
## Avoiding conflicts with the render function
203216

204217
If you update a property that is also managed by the render function,
205218
you might end up with some unpredictable and confusing bugs because
206219
anytime the component re-renders and that property changes, whatever
207220
value was previously set from `setNativeProps` will be completely
208-
ignored and overridden. [See this example](https://rnplay.org/apps/bp1DvQ)
209-
for a demonstration of what can happen if these two collide - notice
210-
the jerky animation each 250ms when `setState` triggers a re-render.
221+
ignored and overridden.
211222

212223
## setNativeProps & shouldComponentUpdate
213224

website/core/Marked.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var Header = require('Header');
1515
var Prism = require('Prism');
1616
var React = require('React');
1717
var WebPlayer = require('WebPlayer');
18+
var SnackPlayer = require('SnackPlayer');
1819

1920
/**
2021
* Block-Level Grammar
@@ -842,6 +843,12 @@ Parser.prototype.tok = function() {
842843
);
843844
}
844845

846+
if (lang && lang.indexOf('SnackPlayer') === 0) {
847+
return (
848+
<SnackPlayer params={lang.split('?')[1]}>{text}</SnackPlayer>
849+
);
850+
}
851+
845852
return <Prism>{text}</Prism>;
846853
}
847854
case 'table': {

0 commit comments

Comments
 (0)