反应原生动画滞后-通过函数调用防止重新渲染

时间:2019-07-23 07:04:21

标签: react-native

上下文

我想获取一个倒计时值,然后将其作为道具传递给动画进度条的单独组件。 data.json包含两种类型的元素:

  • 文本
  • 问题

文本将为用户提供解释。当用户按下按钮时,可以显示另一个文本或一个问题。当有问题时,用户将有一定的时间来回答。进度条将指示剩余时间,并且仅在当前元素是问题时才显示。

问题

我的问题是当前值的屏幕更新非常慢,我看不到原因。这是我的代码的简化版本。进度条组件将替换<Text>{this.state.value}</Text>函数中的renderButtons

版本

我正在运行本机0.60。

更新1

我发现,当我通过countdown事件触发onPress函数时,它起作用了。但是,如果我直接调用它,则不会。这是为什么?没有onPress

,我怎么能做到呢?

更新2

问题在于,由于动画,状态值被更新,并且触发了小夜曲,这导致每次调用该函数,从而导致滞后。这种解决方法似乎有所帮助,但感觉很丑。

有什么更好的方法来处理重新渲染问题?

countdown = type => {
    if (!this.state.countdownRunning) {
      this.setState({ countdownRunning: true });
      if (type === 'question') {
        this.state.percent.addListener(({ value }) => this.setState({ value }));

        Animated.timing(
          // Animate value over time
          this.state.percent, // The value to drive
          {
            toValue: 0, // Animate to final value of 1
            duration: 25000,
            easing: Easing.linear
          }
        ).start(() => {
          console.log('Animation DONE');
          this.setState({ value: 100, percent: new Animated.Value(100) });
          this.onPressNext();
          this.setState({ countdownRunning: false });
        }); // Start the animation
      }
    }
  };

滞后

import React, { Component } from 'react';
import { View, Text, StyleSheet, Animated, Easing } from 'react-native';
import { Button } from 'react-native-paper';
import Card from '../components/Card';
import data from '../data/data.json';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF'
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5
  },
  surface: {
    padding: 20,
    margin: 20,
    borderRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    elevation: 12
  }
});

class Home extends Component {
  constructor(props) {
    super(props);
    this.countdown = this.countdown.bind(this);
    this.state = {
      i: 0,
      questions: data,
      value: 100,
      percent: new Animated.Value(100)
    };
  }

  onPressNext = () => {
    const { i } = this.state;

    if (i < 17) {
      this.setState({ i: i + 1 });
    } else {
      this.setState({ i: 0 });
    }
  };

  onPressBack = () => {
    const { i } = this.state;

    if (i > 0) {
      this.setState({ i: i - 1 });
    } else {
      this.setState({ i: 17 });
    }
  };

  countdown = type => {
    if (type === 'question') {
      this.state.percent.addListener(({ value }) => this.setState({ value }));

      Animated.timing(
        // Animate value over time
        this.state.percent, // The value to drive
        {
          toValue: 0, // Animate to final value of 1
          duration: 25000,
          easing: Easing.linear
        }
      ).start(); // Start the animation
    }
  };

  renderButtons = type => {
    if (type === 'question') {
      this.countdown(type);
      return (
        <View>
          <Text>{this.state.value}</Text>
        </View>
      );
    }

    return (
      <View style={{ flexDirection: 'row' }}>
        <Button mode="text" onPress={() => this.onPressBack()}>
          Zurück
        </Button>
        <Button mode="contained" onPress={() => this.onPressNext(type)}>
          Weiter
        </Button>
      </View>
    );
  };

  render() {
    const { i, questions } = this.state;
    const { type, header, content } = questions.data[i.toString()];

    return (
      <View style={styles.container}>
        <View style={{ flex: 2, justifyContent: 'flex-end' }}>
          <Card>
            <Text>{header}</Text>
            <Text>{content}</Text>
          </Card>
        </View>
        <View style={{ flex: 2 }}>{this.renderButtons(type)}</View>
      </View>
    );
  }
}

export default Home;

没有落后

import React, { Component } from 'react';
import { View, Text, StyleSheet, Animated, Easing } from 'react-native';
import { Button } from 'react-native-paper';
import Card from '../components/Card';
import data from '../data/data.json';

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF'
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10
  },
  instructions: {
    textAlign: 'center',
    color: '#333333',
    marginBottom: 5
  },
  surface: {
    padding: 20,
    margin: 20,
    borderRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    elevation: 12
  }
});

class Home extends Component {
  constructor(props) {
    super(props);
    this.countdown = this.countdown.bind(this);
    this.state = {
      i: 0,
      questions: data,
      value: 100,
      percent: new Animated.Value(100)
    };
  }

  onPressNext = () => {
    const { i } = this.state;

    if (i < 17) {
      this.setState({ i: i + 1 });
    } else {
      this.setState({ i: 0 });
    }
  };

  onPressBack = () => {
    const { i } = this.state;

    if (i > 0) {
      this.setState({ i: i - 1 });
    } else {
      this.setState({ i: 17 });
    }
  };

  countdown = type => {
    if (type === 'question') {
      this.state.percent.addListener(({ value }) => this.setState({ value }));

      Animated.timing(
        // Animate value over time
        this.state.percent, // The value to drive
        {
          toValue: 0, // Animate to final value of 1
          duration: 25000,
          easing: Easing.linear
        }
      ).start(); // Start the animation
    }
  };

  renderButtons = type => {
    if (type === 'question') {
      return (
        <View>
          <Text>{this.state.value}</Text>
          <Button mode="contained" onPress={() => this.countdown(type)}>
            Weiter
          </Button>
        </View>
      );
    }

    return (
      <View style={{ flexDirection: 'row' }}>
        <Button mode="text" onPress={() => this.onPressBack()}>
          Zurück
        </Button>
        <Button mode="contained" onPress={() => this.onPressNext(type)}>
          Weiter
        </Button>
      </View>
    );
  };

  render() {
    const { i, questions } = this.state;
    const { type, header, content } = questions.data[i.toString()];

    return (
      <View style={styles.container}>
        <View style={{ flex: 2, justifyContent: 'flex-end' }}>
          <Card>
            <Text>{header}</Text>
            <Text>{content}</Text>
          </Card>
        </View>
        <View style={{ flex: 2 }}>{this.renderButtons(type)}</View>
      </View>
    );
  }
}

export default Home;

0 个答案:

没有答案