2017-10-14 29 views
0

私は、この反応するネイティブアプリでのプログラムの流れを理解するのが少し難しいです。Render and Constructor in react-native ordering console.log

私は理解するために、アプリケーションからconsole.logステートメントを出しました。

したがって、コンストラクタ内の状態をlat:0、long:0、err:null、およびマーカー:[]に初期化します。次に、コンストラクタで、APIメソッドを呼び出してすべての場所を取得し、マーカーメソッドを設定します。

renderメソッドから

//

[] 
 
[] 
 
[]

//次にコンストラクタ非同期メソッドの戻りを、私たちは、マーカー

{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

は典型的には、非同期のコール

おかげrender()の最初の呼び出しの直後に呼び出されcomponentDidMount()ライフサイクル法、に配置され反応します。 constructorは、初期化コンポーネント、つまりコンポーネントstateを初期化するもので、propsbindコンポーネントメソッドに渡されたときにsuperを呼び出します。 navigatorfetchAPIへの呼び出しを含め、すべての非同期コールをcomponentDidMountに移動し、stateを初期化してもrenderにエラーが発生しないようにします。 Tyler McGinnis氏は次のように書いていますthis post

AJAXリクエストはcomponentDidMountライフサイクルイベントに入れる必要があります。このため、いくつかの理由があり

ファイバー、のリアクト和解アルゴリズムの次の実装では、起動とパフォーマンスの利点のために、必要に応じてレンダリングを停止する能力を持つことになります。これのトレードオフの1つは、AJAXリクエストを作成する意味がある他のライフサイクルイベントであるcomponentWillMountが「非決定的」であるということです。これが意味することは、Reactが、必要なときにいつでも、componentWillMountをさまざまな時に呼び出すことができるということです。これは明らかにAJAXリクエストのための悪い公式となるでしょう。

コンポーネントがマウントされる前にAJAXリクエストが解決しないことを保証することはできません。そうした場合、それはアンマウントされたコンポーネントにsetStateを実行しようとしていることを意味します。これは動作しないだけでなく、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

あなたは 'constructor'で' state'の値を数回明示的にリセットしようとしているように見えますが、これはアンチパターンです。コンストラクタで 'this.state' ** once **を呼び出して' state'を初期化し、他のコンポーネントメソッドで 'setState'を使って実際に状態を更新する必要があります。 –

+0

ありがとう、私は助けていただきありがとうございます。それについては今すぐ行って、それがどのようになっているかを教えてくれるでしょう。ありがとう! – SwimmingG

+0

こんにちはパーカー、助けてくれてありがとう。たとえそれが異なった特性であったとしても、州を何度か設定するのは奇妙に思われました。ありがとう、私はそれを試みます。 – SwimmingG