1

次のような署名を持つスナックバーのようなステータス メッセージ コンポーネントを作成しようとしています。

<StatusMsg
 open={this.state.isOpen}
 message={this.state.msg}
 onRequestClose={someFunc}
 />

"open" が true に設定されている場合、メッセージは画面にアニメーション表示され、一定時間そこにとどまり、その後再びアニメーション表示されなくなります。

したがって、以下のコードは正常に動作しますが、かなり一般的な使用例を除きます。古いメッセージが画面外にアニメーション化される前に、呼び出し元のコンポーネントが新しいメッセージを設定する場合。その場合、以下のコードは単に現在表示されているメッセージを置き換え、同じタイマーを使用します。

理想的には、新しいメッセージが追加されると、古いメッセージが最初に画面外でアニメーション化され、次に新しいメッセージでアニメーション化されます。(新しいメッセージ テキストが古いメッセージ テキストと同じであっても、これが確実に行われるようにしたいと思います。)

私はこのようなことをする方法を理解できないようです。私の推測では、StatusMsg は実際には、メッセージを含むアニメーション ビューを作成するためのファクトリである必要がありますが、それを機能させる方法がわかりません。具体的には、新しいメッセージの作成時に以前のメッセージを閉じる方法。

class StatusMsg extends Component {
  state = { exited: false, moveHeightAnimated: new Animated.Value(HIDDEN_HEIGHT) }
  timerAutoHide = null;

  componentWillMount() {
    if (!this.props.open) {
      this.setState({ exited: true });
    }
  }

  componentDidMount() {
    if (this.props.open) {
      this.show();
    }
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.open && this.state.exited) {
      this.setState({ exited: false });
    }
  }

  componentDidUpdate(prevProps) {
    if (prevProps.open !== this.props.open) {
      if (this.props.open) {
        this.show();
      } else {
        clearTimeout(this.timerAutoHide);
      }
    }
  }

  componentWillUnmount() {
    clearTimeout(this.timerAutoHide);
  }

  show() {
    const toValue = SHOW_HEIGHT;
    Animated.timing(this.state.moveHeightAnimated, {
        toValue,
        duration: 225,
        easing: Easing.bezier(0.0, 0.0, 0.2, 1),
    }).start(this.setAutoHideTimer);
  }

  hide() {
    const toValue = HIDDEN_HEIGHT;
    Animated.timing(this.state.moveHeightAnimated, {
        toValue,
        duration: 195,
        easing: Easing.bezier(0.4, 0.0, 1, 1),
    }).start(this.onFinishedHiding);
  }

  onFinishedHiding = () => {
    this.setState({ exited: true });
    if (this.props.onRequestClose) {
      this.props.onRequestClose();
    }
  }

  setAutoHideTimer = () => {
    if (!this.props.onRequestClose) {
      return;
    }

    clearTimeout(this.timerAutoHide);
    this.timerAutoHide = setTimeout(() => {
      if (!this.props.onRequestClose) {
        return;
      }

      this.hide();
    }, this.props.autoHideDuration || DEFAULT_AUTOHIDE_DURATION);
  }

  render() {
    if (!this.props.open && this.state.exited) {
      return null;
    }

    return (
      <Animated.View style={[styles.msgContainerStyle, { bottom: this.state.moveHeightAnimated }]} >
        <View style={styles.noticeContainerStyle}>
          <Text style={styles.msgTextStyle}>{this.props.message}</Text>
        </View>
      </Animated.View>
    );
  }
}
4

0 に答える 0