1

Say if my animation is being iterated 20 times, but I don't want all of them playing at the same time. How would I go about triggering that one specific animation that have a value of 1. If I clicked on 1 then the other 19 should not trigger except that 1.

    export default class AnimateScreen extends React.PureComponent {
    constructor(props){

      super(props);

      this.forceUpdateHandler = this.forceUpdateHandler.bind(this);

      this.state = {
      dataSource: '',
      progress: new Animated.Value(0),
    };


    animate = (id) => {

          Animated.timing(this.state.progress, {
            toValue: 1,
            duration: 5000,
            easing: Easing.linear,
          }).start([id]); <!-- Here is my attempt in trying to animate that one specific animation. 


render(){
return(
    <FlatList
               data={this.state.dataSource}
               renderItem={({item}) => 
              <View>
               <View>
                 <Text>Work in progress</Text>
                 <View>
                 <TouchableHighlight
                 onPress={this.animate.bind(this, item.id)}>
                  <Animation
                  progress={this.state.progress}
                  source={require('../tools/animations/heart_icon.json')}
                  />
        </TouchableHighlight>

                   <Text> Hello</Text>

                 </View>

               </View>


               </View>
             }
             keyExtractor={(item, index) => index.toString()}
          />
        );
        }
    }

I tried this out and still, all of the animations triggered. Is there a way to trigger them specifically?

DataSource:

"dataSource":[{"id":"10","images":"Emerson live in the sunshine swim in the sea drink the wild air.jpg","note":"Hello","tag":"sunshine"}


    componentDidUpdate(prevProps, prevState) {
  if (!prevState.dataSource) {

      return fetch(`https://www.website.com/React/json-data.php` , {
       method: 'POST',
       headers: {
         'Accept': 'application/json',
         'Content-Type': 'application/json',
       }

      })
        .then((response) => response.json())
        .then((responseJson) => {
          this.setState({
            dataSource: responseJson,
            },function() {
              // In this block you can do something with new state.
            });
        })
        .catch((error) => {
          console.error(error);
        });
    }
  }
  • It looks like this.state.progress probably gets passed to all your items. I would suggest moving the progress/animation part into the Animation component or set a progress key on each item and have the animation adjust that value. – Matt Aft May 17 '18 at 18:59
  • I am not sure what you mean by the first suggestion, but on the second suggestion do you mean somthing like this: `progress={this.state.progress(this, item.id)}`? @MattAft – Jane.S.Wilson May 17 '18 at 19:25
  • no, one example would be once you get the items you map a progress key onto them `items = items.map(item => ({ ...item, progress: 0 })` so each item will have it's own progress set to 0 then instead of using this.state.progress, you will use item.progress which is unique for each item. – Matt Aft May 17 '18 at 21:02
  • @MattAft This seems like an interesting approach, one question, where would I place that snippet of code? I'm sorry, I am just getting into React Native. – Jane.S.Wilson May 17 '18 at 21:15
  • No worries, can you post more of your code? I'll set it up and post it as an answer below – Matt Aft May 17 '18 at 21:49
  • @MattAft I posted more of my code above – Jane.S.Wilson May 17 '18 at 22:08

1 Answers1

1

Basically you can add progress key to each item in the dataSource with an animated value to 0 then on click you will animate that item's progress. It should roughly look like this:

export default class AnimateScreen extends React.PureComponent {
  constructor(props){

    super(props);

    this.forceUpdateHandler = this.forceUpdateHandler.bind(this);

    this.state = {
      dataSource: [],
      progress: new Animated.Value(0),
    };

    componentDidUpdate(prevProps, prevState) {
      if (!prevState.dataSource) {

        return fetch(`https://www.website.com/React/json-data.php` , {
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'Content-Type': 'application/json',
          }

        })
        .then((response) => response.json())
        .then((responseJson) => {
          this.setState({
            dataSource: responseJson.map(item => ({ ...item, progress: new Animated.Value(0) })), // Add progress key
          },function() {
            // In this block you can do something with new state.
          });
        })
        .catch((error) => {
          console.error(error);
        });
      }
    }


    animate = (item) => {
      Animated.timing(item.progress, {
        toValue: 1,
        duration: 5000,
        easing: Easing.linear,
      }).start(); <!-- Here is my attempt in trying to animate that one specific animation. 


      render(){
        return(
          <FlatList
            data={this.state.dataSource}
            renderItem={({item}) => 
            <View>
              <View>
                <Text>Work in progress</Text>
                <View>
                  <TouchableHighlight
                    onPress={() => this.animate(item)}>
                    <Animation
                      progress={item.progress}
                      source={require('../tools/animations/heart_icon.json')}
                    />
                  </TouchableHighlight>

                  <Text> Hello</Text>

                </View>

              </View>


            </View>
          }
          keyExtractor={(item, index) => index.toString()}
        />
      );
    }
  }
Matt Aft
  • 8,742
  • 3
  • 24
  • 37
  • My dataSource is basically a JSON file, I'll updated in my code above. Also, what do those `...` dots mean by `item`? – Jane.S.Wilson May 17 '18 at 22:40
  • Ok i updated my answer to include your fetch, the dots is an es6 spread. it's basically grabbing everything from item and creating a new object with the progress key included: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax – Matt Aft May 17 '18 at 23:20
  • This is great, I haven't tested the code yet because I have to rearrange some code. Since I am using dataSource for the rest of my JSON data I renamed it to this: `id: responseJson.map(item => ({ ...item, progress: new Animated.Value(0) }))` hopefully that works – Jane.S.Wilson May 17 '18 at 23:37
  • hmm not sure why you would need to rename it, everything else is still there. it's literally just adding progress to each item – Matt Aft May 17 '18 at 23:40
  • ahh you're right. Also I got an error when I ran the code: `undefined is not an object (evaluating 'singleValue.stopTracking')` – Jane.S.Wilson May 17 '18 at 23:55
  • Actually never mind, I needed to change the `data` to the correct datasource. Thank you so much! You have no idea how much trouble this was! – Jane.S.Wilson May 18 '18 at 00:36
  • I have one more question, if you don't mind me asking. How would I go about undoing the animation? Like setting it back to it's first state? – Jane.S.Wilson May 18 '18 at 00:41
  • the `.start()` can take a function as a callback which gets called once the animation is finished. I believe you can just set the value back to 0 once the animation is done to "reset" it. `.start(() => item.progress.setValue(0))` – Matt Aft May 18 '18 at 17:06