Skip to content

[docs] Move away from rnplay to snack, with embedded examples! #13285

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
168 changes: 80 additions & 88 deletions docs/Animations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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}
Expand All @@ -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.
Expand Down Expand Up @@ -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})
Expand All @@ -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)
Expand Down Expand Up @@ -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.
51 changes: 31 additions & 20 deletions docs/DirectManipulation.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -105,7 +108,7 @@ class MyButton extends React.Component {
}
}

class App extends React.Component {
export default class App extends React.Component {
render() {
return (
<TouchableOpacity>
Expand All @@ -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`.
Expand All @@ -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);
}

Expand All @@ -147,8 +152,17 @@ class MyButton extends React.Component {
)
}
}

export default class App extends React.Component {
render() {
return (
<TouchableOpacity>
<MyButton label="Press me!" />
</TouchableOpacity>
)
}
}
```
[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.
Expand All @@ -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 (
<View style={styles.container}>
<TextInput ref={component => this._textInput = component}
style={styles.textInput} />
<View style={{flex: 1}}>
<TextInput
ref={component => this._textInput = component}
style={{height: 50, flex: 1, marginHorizontal: 20, borderWidth: 1, borderColor: '#ccc'}}
/>
<TouchableOpacity onPress={this.clearText}>
<Text>Clear text</Text>
</TouchableOpacity>
Expand All @@ -197,17 +211,14 @@ class App extends React.Component {
}
}
```
[Run this example](https://rnplay.org/plays/pOI9bA)

## 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. [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

Expand Down
7 changes: 7 additions & 0 deletions website/core/Marked.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -842,6 +843,12 @@ Parser.prototype.tok = function() {
);
}

if (lang && lang.indexOf('SnackPlayer') === 0) {
return (
<SnackPlayer params={lang.split('?')[1]}>{text}</SnackPlayer>
);
}

return <Prism>{text}</Prism>;
}
case 'table': {
Expand Down
Loading