Course Menu

Using and Understanding setNativeProps

To understand how animated works you must first understand setNativeProps. This is what Animated uses to bypass setState. It sends new properties over the bridge directly to the native world.

DO NOTE: if you use setNativeProps to set a prop on the native side, and then a setState happens and the prop you've set natively is set on the particular element it will be overridden, or unless you pass back the value you set on the native side.

We'll be looking at trivial cases, however this is how Animated works. In the render it always derives the current prop values which are the same values it's already sent to the native world using setNativeProps.

Lets take a look at some code first. We setup a ScrollView with an animated background on scroll. In order to call setNativeProps we need to get access to the view instance and we do that by getting a ref.

import React, { Component } from "react";
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  Animated,
  ScrollView,
  TouchableOpacity,
} from "react-native";

export default class animations extends Component {
  state = {
    animation: new Animated.Value(0),
  };
  _enabled = true;

  render() {
    const bgInterpolate = this.state.animation.interpolate({
      inputRange: [0, 3000],
      outputRange: ["rgb(255,99,71)", "rgb(99,71,255)"],
    });
    const scrollStyle = {
      backgroundColor: bgInterpolate,
    };
    return (
      <View style={styles.container}>
        <TouchableOpacity onPress={this.handleToggle}>
          <Text>Toggle</Text>
        </TouchableOpacity>

        <ScrollView
          style={styles.scroll}
          ref={(scroll) => (this._scroll = scroll)}
          scrollEventThrottle={16}
          onScroll={Animated.event([
            {
              nativeEvent: {
                contentOffset: {
                  y: this.state.animation,
                },
              },
            },
          ])}
        >
          <Animated.View style={[styles.fakeContent, scrollStyle]} />
        </ScrollView>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 50,
  },
  scroll: {
    flex: 1,
    opacity: 1,
  },
  hide: {
    opacity: 0,
  },
  show: {
    opacity: 1,
  },
  fakeContent: {
    height: 3000,
    backgroundColor: "tomato",
  },
});

Here is where the magic happens.

Lets start first with just one setNativeProp call.

handleToggle = () => {
  this._enabled = !this._enabled;
  this._scroll.setNativeProps({
    scrollEnabled: this._enabled,
  });
};

We have this._enabled default to true on our component instance. We then toggle it and call setNativeProps and pass in an object of props we want to set. In our case we are just setting a single one and that's scrollEnabled. This will allow us to lock scrolling capabilities.

We can see it in action here, we lock the scroll without passing in a prop to our ScrollView, and without causing a setState to happen.

We can additionally override more than one prop at once, including the style prop. Understand though that you are REPLACING the prop in the native side. So if you have specific styling you need to preserve you will need to manage and send the entire new style, including the values you aren't overriding.

You can see that here, we create a style tag and pass in our styles.scroll, then whether or not we are disabled we pass in a hide or show styling which will toggle the opacity. We'll also still disable the scroll. This whole concept is foundational to how the JavaScript version of Animated works and how we can craft our own animations.

handleToggle = () => {
  this._enabled = !this._enabled;
  let style = [styles.scroll];

  if (!this._enabled) {
    style.push(styles.hide);
  } else {
    style.push(styles.show);
  }

  this._scroll.setNativeProps({
    scrollEnabled: this._enabled,
    style,
  });
};

Live Demo Code