简体   繁体   English

React Native:更换屏幕时如何防止 state 重置?

[英]React Native: How to prevent state reset when changing screens?

I am having trouble when changing screens after the user access a card.用户访问卡片后更改屏幕时遇到问题。 The component set of states resets whenever the client accesses a card, changes the screen, and returns to the same component before.每当客户端访问卡片、更改屏幕并返回到之前的相同组件时,组件状态集都会重置。

Here is how the app works.这是该应用程序的工作方式。 The client access a list of quotes (QuotesRequestedListScreen) that they requested.客户端访问他们请求的报价列表 (QuotesRequestedListScreen)。 This said list is loaded from Firebase, and thus the state to indicate loading activity is set to true at first.该列表是从 Firebase 加载的,因此首先将指示加载活动的 state 设置为 true。 After the load finishes, then the app shows all the data in cards.加载完成后,应用程序会在卡片中显示所有数据。 After the client clicks on the card, it changes the screen and displays the card info.客户端点击卡片后,画面切换,显示卡片信息。 However, if the client returns to the previous screen, the screen shows the loading activity icon forever until changing screens again.但是,如果客户端返回到前一个屏幕,该屏幕将永远显示加载活动图标,直到再次切换屏幕。

I have tried to use State Persistance given by React Navigation , but it did not work when I was trying to return to the quote list screen (QuotesRequestedListScreen).我尝试使用由 React Navigation 提供的 State 持久性,但是当我尝试返回报价列表屏幕(QuotesRequestedListScreen)时它不起作用。

Does someone know what is the best way to keep the states when changing screens?有人知道在更改屏幕时保持状态的最佳方法是什么? Thanks!谢谢!

Main Quote Screen主报价屏幕

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;

The problem is that you're creating a component inside another component.问题是您正在另一个组件中创建一个组件。 Your function component QuotesRequestedScreen is defined inside the QuoteScreen function.您的 function 组件QuotesRequestedScreenQuoteScreen function 中定义。

You should NEVER define components inside other components or your state will be lost on re-render due to remount.永远不应该在其他组件中定义组件,否则您的 state 将由于重新安装而在重新渲染时丢失。 Just move the QuotesRequestedScreen to outside the QuoteScreen function and then it'll work as expected.只需将QuotesRequestedScreen移到QuoteScreen function 之外,它就会按预期工作。

More information from React Navigation docs https://reactnavigation.org/docs/troubleshooting#screens-are-unmountingremounting-during-navigation更多信息来自 React Navigation 文档https://reactnavigation.org/docs/troubleshooting#screens-are-unmountingremounting-during-navigation

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM