2017-10-14 94 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