React Native Component не выполняет повторную визуализацию при изменении состояния - PullRequest
0 голосов
/ 01 октября 2019

Независимо от того, что я пытаюсь, мне не удается обновить компонент. Ниже мой код:

import React, { Component } from "react";
import { StyleSheet, View, TouchableOpacity, Image, Text } from "react-native";
import PropTypes from "prop-types";

import { toggleSound } from "logic/Music.js";
import soundOn from "assets/img/swipe.png";
import soundOff from "assets/img/illum-triangle.png";

export default class GlobalSoundButton extends Component {
  constructor(props) {
    super(props);
    this.state = {
      audioOff: this.props.audioOff
    };
  }

  componentDidUpdate = prevProps => {
    if (prevProps.audioOff !== this.props.audioOff) {
      this.setState({ audioOff: this.props.audioOff }, () => {
        console.log("SWITCHING STATE", this.state);
      };
      this.forceUpdate();
    }
  };

  render() {
    return (
      <View style={styles.soundButtonWrapper} key={this.props.name}>
        <TouchableOpacity
          style={styles.soundButtonPress}
          activeOpacity={0.8}
          onPress={() => {
            toggleSound(this.props.sounds);
          }}
        >
          <Image
            style={styles.soundButton}
            source={this.state.audioOff ? soundOff : soundOn}
          ></Image>
          <Text style={styles.text}>
            Audio {this.state.audioOff ? "off" : "on"}
          </Text>
        </TouchableOpacity>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  soundButtonWrapper: {
    width: "100%",
    height: 40,
    position: "absolute",
    top: 20
  },
  soundButtonPress: {
    width: 40,
    height: 40,
    position: "absolute",
    right: 20
  },
  soundButton: {
    width: 40,
    height: 40,
    tintColor: "#59BC92"
  },
  text: {
    width: 120,
    height: 40,
    position: "absolute",
    right: 80,
    color: "white"
  }
});

GlobalSoundButton.propTypes = {
  sounds: PropTypes.array
};

Странная часть в том, что я использую этот компонент на двух разных экранах, и в одном случае он работает абсолютно нормально, но на другом экране он не рендерится, когдазвук меняется.

Каждый раз, когда я нажимаю на него, реквизиты обновляются, поэтому я ЗНАЮ, что состояние обновляется. Журнал консоли всегда записывает другое состояние, поэтому я знаю, что состояние обновляется. Я также попробовал forceUpdate() и добавил ключ (вы можете увидеть ключ в коде), но это не помогает.

Я в растерянности здесь. Кто-нибудь сталкивался с такой же проблемой или может помочь? Я также знаю, что есть несколько вопросов, подобных этому, но никто не ответил на мои вопросы, поэтому мне пришлось написать свой собственный.

Я удалил много несвязанного кода здесь, но в основном я передаю реквизиты следующим образом вмой HomeScreen ( это GlobalSoundButton, и в этом случае это работает):

import GLOBAL from "logic/GlobalState.js";

export default class HomeScreen extends Component {
  constructor(props) {
    super(props);
    this.state = {
      audioOff: false,
    };
  }

  async componentDidMount() {
    let audioOff;
    try {
      audioOff = await retrieveData("audioOff");
    } catch (err) {
      console.error(err);
    }

    this.setState(
      {
        audioOff: audioOff === "true"
      });

  render() {
    GLOBAL.homeScreen = this;

    return (
      <View style={styles.container}>
        <View style={styles.bg}>
          <ImageBackground
            source={pattern}
            style={styles.img}
            resizeMode="repeat"
            imageStyle={styles.innerImg}
          />
        </View>
        <View style={styles.container}>
          <GlobalSoundButton
            sounds={this.state.allSounds}
            audioOff={this.state.audioOff}
            name="HomeScreenKey"
          ></GlobalSoundButton>
          <Text
            style={[styles.smallText, styles.ppText]}
            onPress={() =>
              Linking.openURL(
                "https://privacy-illuminati-flip.netlify.com"
              ).catch(err => console.error("An error occurred", err))
            }
          >
            Privacy Policy
          </Text>
          <Text style={styles.welcome}>Illuminati Flip</Text>
          <TouchableWithoutFeedback
            onPressIn={evt => this.grabFinger(evt)}
            onPressOut={evt => this.swipe(evt)}
            pressRetentionOffset={{ top: 100, left: 0, bottom: 100, right: 0 }}
          >
            <View style={styles.swipeArea}>
              <View style={styles.gridSelection}>
                <Animated.View
                  pointerEvents={"none"}
                  style={{
                    ...styles.innerGridSelection,
                    transform: [{ translateX: this.springValue }]
                  }}
                >
                  {difficulties}
                </Animated.View>
              </View>
              <View style={styles.margin}>
                <Animated.Image
                  source={swipeFinger}
                  style={{
                    ...styles.hand,
                    transform: [
                      {
                        translateX: this.fingerValue.interpolate({
                          inputRange: [-1, 1],
                          outputRange: [-15, 15]
                        })
                      }
                    ]
                  }}
                />
                <Text style={styles.smallText}>Swipe to change difficulty</Text>
              </View>
            </View>
          </TouchableWithoutFeedback>
          <TouchableOpacity
            activeOpacity={0.8}
            onPress={() => {
              this.checkTutorial();
            }}
          >
            <Text style={styles.button}>Begin Ceremony</Text>
          </TouchableOpacity>
          <Text
            style={[styles.smallText, styles.musicText]}
            onPress={() =>
              Linking.openURL("https://fanlink.to/triobgame").catch(err =>
                console.error("An error occurred", err)
              )
            }
          >
            Music by @triobelisk
          </Text>
          <Text
            style={[styles.smallText, styles.devText]}
            onPress={() =>
              Linking.openURL("https://twitter.com/iamjohnhult").catch(err =>
                console.error("An error occurred", err)
              )
            }
          >
            Developed by @iamjohnhult
          </Text>
        </View>


      </View>
    );
  }
}

const styles = StyleSheet.create({
  ...
});

Разница в другом компоненте, где он не работает, я отрисовываю так:

import GLOBAL from "logic/GlobalState.js";

<GlobalSoundButton
   sounds={this.state.allSounds}
   audioOff={GLOBAL.homeScreen.state.audioOff}
   name="GameScreenKey"
></GlobalSoundButton>

И GlobalState.js выглядит следующим образом:

module.exports = {
  homeScreen: null
};
...