簡體   English   中英

React-Native:警告:無法對卸載的組件執行 React 狀態更新

[英]React-Native: Warning: Can't perform a React state update on an unmounted component

當我嘗試從一個屏幕轉換到另一個屏幕時,我收到以下錯誤消息:

在此處輸入圖片說明

這發生在游戲應用程序中,其中多個手機參與游戲並且根據它們在游戲中的角色以及該手機是托管游戲還是訪客而具有不同的屏幕。

下圖顯示了當我嘗試到達下一個屏幕(在左側手機上)時的錯誤消息。 左側手機的屏幕應該與右側的相同,但沒有“下一輪”和“結束游戲”按鈕。 但我收到一個完全不同的屏幕,並顯示錯誤消息:

在此處輸入圖片說明

這是前一個屏幕的代碼,應該將手機導航到這個“分數”屏幕:

 import React, {Component} from 'react'; import {AppRegistry, View, Text, ScrollView, StyleSheet} from 'react-native'; import {CardFlip1} from '../components/CardFlip1'; import {CardFlip2} from '../components/CardFlip2'; import colors from '../config/colors'; import {PrimaryButton} from '../components/PrimaryButton'; import AsyncStorage from '@react-native-community/async-storage'; import Orientation from 'react-native-orientation-locker'; window.navigator.userAgent = 'react-native'; import io from 'socket.io-client/dist/socket.io'; class judge_screen extends Component { constructor (props) { super(props); this.state = { game_round: '', player1: '', player2: '', label1: '', label2: '', current_user: '' } } componentWillMount = () => { this.getActives(); } componentDidMount() { Orientation.lockToLandscape(); this.socket = io("socket address is here", { jsonp: false }); } getActives = async () => { let user = await AsyncStorage.getItem('email'); let player_1 = await AsyncStorage.getItem('Player1'); let player_2 = await AsyncStorage.getItem('Player2'); let round = await AsyncStorage.getItem('Round'); this.setState({game_round: round}); this.setState({player1: player_1}); this.setState({player2: player_2}); var label_start = "Choose "; var label_end = "'s fate"; var player_1_name = this.state.player1; var player_2_name = this.state.player2; var label1_str = label_start.concat(player_1_name, label_end); this.setState({label1: label1_str}); var label2_str = label_start.concat(player_2_name, label_end); this.setState({label2: label2_str}); } player1Win = async () => { let host = await AsyncStorage.getItem('host'); if (host == 'yes') { let user = await AsyncStorage.getItem('email'); this.setState({current_user: user}); } else { let user = await AsyncStorage.getItem('users_id'); this.setState({current_user: user}); } var user_fix = this.state.current_user; let player_name = await AsyncStorage.getItem('Player1'); AsyncStorage.setItem('Winner', player_name); fetch('fetch address is here', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application.json', }, body: JSON.stringify({ email: user_fix, Name: player_name, Host: host }) }).then((response) => response.json()) .then((responseJson) => { if (host == 'yes') { this.socket.emit('end_round', 'end'); this.props.navigation.navigate('end_round_host_screen'); } else { // This is the navigation to the screen getting the error: this.socket.emit('end_round', 'end'); this.props.navigation.navigate('end_round_guest_screen'); } }).catch((error) => { console.error(error); }); } player2Win = async () => { let host = await AsyncStorage.getItem('host'); if (host == 'yes') { let user = await AsyncStorage.getItem('email'); this.setState({current_user: user}); } else { let user = await AsyncStorage.getItem('users_id'); this.setState({current_user: user}); } var user_fix = this.state.current_user; let player_name = await AsyncStorage.getItem('Player2'); AsyncStorage.setItem('Winner', player_name); fetch('fetch address is here', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application.json', }, body: JSON.stringify({ email: user_fix, Name: player_name, Host: host }) }).then((response) => response.json()) .then((responseJson) => { if (host == 'yes') { this.socket.emit('end_round', 'end'); this.props.navigation.navigate('end_round_host_screen'); } else { // This is the navigation to the screen getting the error: this.socket.emit('end_round', 'end'); this.props.navigation.navigate('end_round_guest_screen'); } }).catch((error) => { console.error(error); }); } render() { return ( <ScrollView> <View style={{flexDirection: 'row'}}> <View style={styles.container}> <Text style={[styles.text]}> {this.state.player1} </Text> <CardFlip1 /> <PrimaryButton onPress={() => this.player1Win()} label={this.state.label1} > </PrimaryButton> </View> <View style={styles.container}> <Text style={[styles.text]}> {this.state.player2} </Text> <CardFlip2 /> <PrimaryButton onPress={() => this.player2Win()} label={this.state.label2} > </PrimaryButton> </View> </View> </ScrollView> ); } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: colors.backgroundColor, margin: 10, paddingBottom: 5, borderWidth: 1, borderColor: colors.borderColor, }, text: { fontSize: 18, color: colors.primaryText, marginTop: 10, }, textPadding: { paddingBottom: 10, }, headingText: { fontSize: 24, fontWeight: '500', color: colors.primaryText, margin: 10, }, textMarginHorizontal: { marginHorizontal: 10, }, }) export default judge_screen;

這是我試圖導航到的“end_round_guest_screen”的代碼:

 import React, {Component} from 'react'; import {View, Text, ScrollView, StyleSheet} from 'react-native'; import colors from '../config/colors'; import {PrimaryButton} from '../components/PrimaryButton'; import {ScoreBoardGuest} from '../components/ScoreBoardGuest'; import AsyncStorage from '@react-native-community/async-storage'; import Orientation from 'react-native-orientation-locker'; window.navigator.userAgent = 'react-native'; import io from 'socket.io-client/dist/socket.io'; class end_round_guest_screen extends Component { constructor (props) { super(props); this.state = { game_round: '', winner: '' } } componentWillMount = () => { this.getActives(); this.getWinner(); } componentDidMount() { Orientation.unlockAllOrientations(); this.socket = io("socket address is here", { jsonp: false }); this.socket.on('next_round', () => this.nextRound()); this.socket.on('end_game', () => this.endGame()); } getActives = async () => { let round = await AsyncStorage.getItem('Round'); this.setState({game_round: round}); } getWinner = async () => { let user = await AsyncStorage.getItem('users_id'); //let host = await AsyncStorage.getItem('host'); fetch('fetch address is here', { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application.json', }, body: JSON.stringify({ email: user }) }).then((response) => response.json()) .then((responseJson) => { this.setState({winner: responseJson}); }).catch((error) => { console.error(error); }); } nextRound = () => { this.props.navigation.navigate('round_start_guest_screen'); } endGame = () => { this.props.navigation.navigate('end_game_guest_screen'); } render() { return ( <ScrollView> <View style={{alignItems: 'center'}}> <Text style={styles.headingText}> Round {this.state.game_round} </Text> <Text style={styles.text}> {this.state.winner} wins this round! </Text> </View> <View style={styles.container}> <ScoreBoardGuest /> </View> </ScrollView> ); } } const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', backgroundColor: colors.backgroundColor, margin: 10, paddingVertical: 5, borderWidth: 1, borderColor: colors.borderColor, }, text: { fontSize: 18, color: colors.primaryText, marginTop: 10, }, headingText: { fontSize: 24, fontWeight: '500', color: colors.primaryText, margin: 10, }, }) export default end_round_guest_screen;

“end_round_guest_screen”在沒有加載任何狀態的情況下顯示一兩秒鍾,然后轉到帶有錯誤消息的“回牌”屏幕。

end_round_guest_screen顯示錯誤發生在end_round_guest_screen 根據您的描述,它在導航到“Card Back”並出現錯誤之前顯示了 2 秒,我假設它發生在 fetch 回調中的this.setState({winner: responseJson})

如果獲取請求仍在等待響應,則可能會發生這種情況,然后調用 nextRound 或 endGame 處理程序,從而觸發導航,從而觸發卸載。 到 fetch 獲取數據並即將調用 setState 時,該組件已不再掛載。

一般有兩種方法可以解決這個問題。

1.) (Anti-pattern) 使用 componentDidMount/componentWillUnmount 回調跟蹤組件是否仍然掛載,然后在調用 setState 之前執行 isMounted 檢查。

componentDidMount() {
    this.isMounted = false
}

componentWillUnmount() {
    this.isMounted = false
}

getWinner = async () => {
    //inside fetch
    if (this.isMounted) {
        this.setState({winner: responseJson})
    }
}

2.)(推薦)使用 componentWillUnmount 回調取消任何掛起的網絡請求。

例如,您可以使用 AbortController 取消 fetch 請求。 有關示例代碼,請參閱https://stackoverflow.com/a/53435967/803865

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM