2017-10-14 97 views
0

我在理解這個反應原生程序中的程序流時有點困難。在react-native排序中的渲染和構造函數console.log

我已將console.log語句放在應用程序中,以嘗試理解。

因此,我將構造函數中的狀態初始化爲lat:0,long:0,err:null和markers:[]。然後在構造函數中調用我的API方法來獲取所有位置並填充標記方法。從打印輸出如下:

//從渲染方法

[] 
 
[] 
 
[]

//然後構造異步方法返回,我們設置標誌

{markers: [{title: "A", coordinate: {latitude: 0, longitude: 1}, description: "abc"}, 
 
{title: "B", coordinate: {latitude: 0, longitude: 1}, description: "abc"}]}

然後我調用渲染方法,我知道這可能是很糟糕的做法,但它只是簡單地嘗試調試,希望標記能夠在地圖上可見。

但是,在這之後,渲染方法繼續打印[],這對我來說看起來很奇怪,因爲我剛剛在構造函數中設置它!

任何幫助,將不勝感激。

import React, { Component } from 'react'; 
 
import { 
 
    Platform, 
 
    StyleSheet, 
 
    Text, 
 
    View 
 
} from 'react-native'; 
 
import MapView from 'react-native-maps'; 
 

 
const styles = StyleSheet.create({ 
 
    container: { 
 
    position: 'absolute', 
 
    top: 0, 
 
    left: 0, 
 
    right: 0, 
 
    bottom: 0, 
 
    justifyContent: 'flex-end', 
 
    alignItems: 'center', 
 
    }, 
 
    map: { 
 
    position: 'absolute', 
 
    top: 0, 
 
    left: 0, 
 
    right: 0, 
 
    bottom: 0, 
 
    }, 
 
}); 
 

 
const instructions = Platform.select({ 
 
    ios: 'Press Cmd+R to reload,\n' + 
 
    'Cmd+D or shake for dev menu', 
 
    android: 'Double tap R on your keyboard to reload,\n' + 
 
    'Shake or press menu button for dev menu', 
 
}); 
 

 
class App extends Component { 
 

 
    constructor(props) { 
 
    super(props); 
 
    this.state = { 
 
     latitude: 0, 
 
     longitude: 0, 
 
     error: null, 
 
     markers: [] 
 
    }; 
 
    navigator.geolocation.getCurrentPosition(
 
     (position) => { 
 
     this.state = { 
 
      latitude: position.coords.latitude, 
 
      longitude: position.coords.longitude, 
 
      error: null, 
 
     }; 
 
     }, 
 
     (error) => this.setState({ error: error.message }), 
 
     { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }, 
 
    ); 
 
    fetch(API_URL) 
 
     .then((response) => response.json()) 
 
     .then((responseJson) => { 
 
     var relevantLocations = [] 
 
     for (var i = 0; i < responseJson.length; i++) { 
 
      var location = responseJson[i]; 
 
      relevantLocations.push({ 
 
      title: location.name, 
 
      coordinate: {latitude: location.latitude, longitude: location.longitude}, 
 
      description: "test" + i 
 
      }); 
 
     } 
 
     console.log("Setting state"); 
 
     this.state = { 
 
      markers: relevantLocations 
 
     }; 
 
     console.log(this.state); 
 
     this.render(); 
 
     }) 
 
     .catch((error) => { 
 
     console.error(error); 
 
     }); 
 
    } 
 

 
    onRegionChange = (region) => { 
 
    this.setState({ region }); 
 
    } 
 

 
    onPress =() => { 
 
    } 
 

 
    render() { 
 
    console.log(this.state.markers); 
 
    return (
 
     <View style={styles.container}> 
 
     <MapView style={styles.map} 
 
      onRegionChange={this.onRegionChange} 
 
      onPress={this.onPress} 
 
     > 
 
     {this.state.markers.map(marker => { 
 
      return <MapView.Marker 
 
       key={marker} 
 
       coordinate={marker.coordinate} 
 
       title={marker.title} 
 
       description={marker.description} 
 
      /> 
 
      })} 
 
     </MapView> 
 
     </View> 
 
    ); 
 
    } 
 
} 
 

 
export default App;

它怎麼說,我在構造函數中設置的變量被覆蓋?

由於

回答

2

典型地,異步調用發生反應被放置在componentDidMount()生命週期方法,其獲取對render()初始呼叫之後立即被調用。 constructor用於初始化,即初始化組件state,在任何通過組件方法的props上調用super。我會將您的所有異步呼叫轉移到navigatorfetchAPI,並將其轉換爲componentDidMount,並確保您初始化的任何state不會在render上導致任何錯誤。正如Tyler McGinnis在this post中寫道:

AJAX請求應該放在componentDidMount生命週期事件中。

這有幾個原因,

光纖,未來實施陣營的和解算法,將不得不啓動和停止根據需要的性能優勢渲染能力。其中一個折衷是componentWillMount,另一個生命週期事件,它可能會使AJAX請求變得有意義,將是「非確定性」。這意味着React可能會在不同時間開始調用componentWillMount,只要感覺需要。這顯然是AJAX請求的錯誤公式。

您無法保證AJAX請求在組件掛載之前無法解析。如果確實如此,那就意味着你會試圖在未掛載的組件上設置狀態,這不僅不行,而且React會對你大喊。在componentDidMount中做AJAX將保證有一個組件需要更新。

下面是一個完整的返工示例,使用componentDidMount並在所有異步請求解決後正確設置state

import React, { Component } from 'react'; 
import { 
    Platform, 
    StyleSheet, 
    Text, 
    View 
} from 'react-native'; 
import MapView from 'react-native-maps'; 

const styles = StyleSheet.create({ 
    container: { 
    position: 'absolute', 
    top: 0, 
    left: 0, 
    right: 0, 
    bottom: 0, 
    justifyContent: 'flex-end', 
    alignItems: 'center', 
    }, 
    map: { 
    position: 'absolute', 
    top: 0, 
    left: 0, 
    right: 0, 
    bottom: 0, 
    }, 
}); 

const instructions = Platform.select({ 
    ios: 'Press Cmd+R to reload,\n' + 
    'Cmd+D or shake for dev menu', 
    android: 'Double tap R on your keyboard to reload,\n' + 
    'Shake or press menu button for dev menu', 
}); 

class App extends Component { 

    constructor(props) { 
    super(props); 
    this.state = { 
     latitude: 0, 
     longitude: 0, 
     error: null, 
     markers: [] 
    }; 
    } 

    componentDidMount() { 

    navigator.geolocation.getCurrentPosition(
     (position) => { 

     fetch(API_URL) 
      .then((response) => response.json()) 
      .then((responseJson) => { 
       var relevantLocations = [] 
       for (var i = 0; i < responseJson.length; i++) { 
       var location = responseJson[i]; 
       relevantLocations.push({ 
        title: location.name, 
        coordinate: {latitude: location.latitude, longitude: 
        location.longitude}, 
        description: "test" + i 
       }); 
       } 
      console.log("Setting state"); 
      this.setState({ 
       ...this.state 
       latitude: position.coords.latitude, 
       longitude: position.coords.longitude, 
       markers: relevantLocations 
      }); 
      }) 
      .catch((error) => { 
      console.error(error); 
      }); 

     }, 
     (error) => this.setState({ ...this.state, error: error.message }), 
     { enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 }, 
    ); 


    } 

    onRegionChange = (region) => { 
    this.setState({ region }); 
    } 

    onPress =() => { 
    } 

    render() { 
    console.log(this.state.markers); 
    return (
     <View style={styles.container}> 
     <MapView style={styles.map} 
      onRegionChange={this.onRegionChange} 
      onPress={this.onPress} 
     > 
     {this.state.markers.map(marker => { 
      return <MapView.Marker 
       key={marker} 
       coordinate={marker.coordinate} 
       title={marker.title} 
       description={marker.description} 
      /> 
      })} 
     </MapView> 
     </View> 
    ); 
    } 
} 

export default App; 
+1

它似乎也顯式地試圖在您的'構造函數',這是一個反模式幾次重置'狀態'的值。您應該在構造函數中調用'this.state' ** once **以初始化'state',然後在其他組件方法中使用'setState'來實際更新狀態。 –

+0

謝謝,我感謝幫助。現在就放棄它,並會讓你知道它是如何發展的。謝謝! – SwimmingG

+0

嗨帕克,謝謝你的建議。雖然它是針對不同的屬性,但幾次設置狀態似乎很奇怪。非常感謝,我會嘗試。 – SwimmingG