React Native:更改屏幕时如何防止状态重置?

时间:2020-07-22 21:42:20

标签: javascript reactjs react-native react-navigation

用户访问卡后更改屏幕时遇到麻烦。每当客户端访问卡,更改屏幕并返回之前的相同组件时,组件状态集就会重置。

这是应用程序的工作方式。客户端访问他们请求的报价列表(QuotesRequestedListScreen)。该列表是从Firebase加载的,因此指示加载活动的状态首先设置为true。加载完成后,该应用程序将显示卡中的所有数据。客户端单击卡后,它将更改屏幕并显示卡信息。但是,如果客户端返回到上一个屏幕,则屏幕将永远显示加载活动图标,直到再次更改屏幕为止。

我曾经尝试使用State Persistance given by React Navigation,但是当我尝试返回报价列表屏幕(QuotesRequestedListScreen)时,此方法不起作用。

有人知道更换屏幕时保持状态的最佳方法是什么吗?谢谢!

主报价屏幕

const QuoteScreen = (props) => {
  
  const QuotesRequestedScreen = () => {
    return (
      <Stack.Navigator headerMode="none" initialRouteName="Quote List">
        <Stack.Screen name="Quote List" component={QuotesRequestedListScreen} />
        <Stack.Screen name="Card" component={QuoteRequestedCardScreen} />
      </Stack.Navigator>
    );
  };

  return (
    <Tab.Navigator initialRouteName="Request Quote">
      <Tab.Screen name="Request Quote" component={RequestQuoteScreen} />
      <Tab.Screen name="Quotes Requested" component={QuotesRequestedScreen} />
    </Tab.Navigator>
  );
};

export default QuoteScreen;

QuotesRequestedListScreen

const QuotesRequestedListScreen = (props) => {
  //Getting userID for the useEffect
  let userId = useSelector((state) => state.user.userId);
  const {height} = Dimensions.get('window');

  //
  ////USESTATES
  //

  const [quoteStatusCards, setQuoteStatusCards] = useState([]);
  const [airportList, setAirportList] = useState([]);
  const [rawQuotes, setRawQuotes] = useState([]);
  const [errorDetector, setErrorDetector] = useState(false);
  const [isLoading, setIsLoading] = useState(true);
  const [isUserLogged, setIsUserLogged] = useState(true);

  //
  ////USEEFFECTS
  //

  useEffect(() => {
    //Function that starts the verification once it has the focus
    const unsubscribe = props.navigation.addListener('focus', () => {

    if (userId !== null) {
        console.log('Entrei aqui');
        getQuotes();
    } else {
        setIsLoading(false);
        setIsUserLogged(false);
    }
    });

    return unsubscribe;
  }, [userId]);

  //
  //// FUNCTIONS
  //

  const getQuotes = async () => {
    await firebase.getQuotesById(userId).then(async (results) => {
      if (results.isError) {
        errorOperationQuote(results.errorMessage);
      } else {
        //Then it tries to get the airportlist from asyncStorage.
        await AsyncStorage.getItem('airportList')
          .then(async (list) => {
            //Checks if the list is empty
            if (list != null) {
              //If it's not, then it checks the last version in the database with the one stored in the asyncstorage
              await firebase.compareAirportListVersion().then((result) => {
                if (result.isError) {
                  //If there are errors, then it reports the error to the user
                  errorOperationQuote(result.errorMessage);
                } else {
                  if (result.success) {
                    //If it's the same version, then it loads inside airportList;
                    setAirportList(JSON.parse(list));
                    setRawQuotes(results.quotes);
                    setIsLoading(false);
                  } else {
                    //If it's not the same version, then it downloads the whole list again.
                    downloadAirportList(results.quotes);
                  }
                }
              });
            } else {
              //If the list's empty, then it downloads the airport
              downloadAirportList(results.quotes);
            }
          })
          .catch((error) => {
            errorOperationQuote(error.errorMessage);
          });
      }
    });
  };

  //Downloads the airport list and set it to the AirportList state.
  const downloadAirportList = async (quotes) => {
    await firebase.getAirports().then((result) => {
      if (result.success) {
        setAirportList(JSON.parse(result.airportList));
        setRawQuotes(quotes);
      } else {
        errorOperationQuote(result.errorMessage);
      }
    });
  };

  //
  ////RETURN
  //

  return (
    <Container>
      <Content contentContainerStyle={styles.quoteCardsContainer}>
        {isLoading ? (
          <View style={styles.loadingErrorContainers}>
            <Spinner style={{alignItems: 'center'}} color={colors.colorRed} />
          </View>
        ) : !isUserLogged ? (
          <View style={styles.loadingErrorContainers}>
            <Text style={styles.errorMessageText}>
              User is not logged in. Please, log in first before checking the
              quotes requested.
            </Text>
            <Button
              onPress={() => {
                props.navigation.navigate('Login');
              }}>
              Login
            </Button>
          </View>
        ) 
///...
      </Content>
    </Container>
  );

}

QuoteRequestedCardScreen

const QuoteRequestedCardScreen = (props) => {
  const [quoteInfo, setQuoteInfo] = useState(props.route.params?.selectedQuote);
  console.log(quoteInfo);

  return (
    <Container>
      <Content style={{marginHorizontal: 10}}>
        <Card>
          <CardItem style={{paddingLeft: 0}} header>
            <View style={{flexDirection: 'row'}}>
              <Button
                onPress={() => props.navigation.navigate('Quote List')}
                transparent>
                <Icon name="arrow-left" type="FontAwesome5" />
              </Button>
              //...
            </View>
          </CardItem>
        </Card>
      </Content>
    </Container>
  );
};

export default QuoteRequestedCardScreen;

1 个答案:

答案 0 :(得分:1)

问题在于您正在另一个组件内创建一个组件。您的功能组件QuotesRequestedScreen是在QuoteScreen函数内部定义的。

您应该从不定义其他组件内部的组件,否则由于重新安装,您的状态将在重新渲染时丢失。只需将QuotesRequestedScreen移动到QuoteScreen函数外部,然后它将按预期工作。

来自React Navigation文档https://reactnavigation.org/docs/troubleshooting#screens-are-unmountingremounting-during-navigation

的更多信息