0

I trying to build a weather app for my training and I have a issues.

I got a Type Error whatever I do. what I intended to do is get a json data from weathermap api and then

show some strings but I couldn't.

here is main content from My app

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



class Content extends Component{
    constructor(props) {
        super(props);

        this.state = {
            data: this.props.weather.main,
        };
    }



    render() {


    return (
        <View style={styles.content}>
            <Text style={styles.city}>City Name</Text>
    <Text style={styles.itemsize}>Weather {this.state.data}</Text>
            <Text style={styles.itemsize}>Description</Text>
            <Text style={styles.itemsize}>Temperature Celsius</Text>
            <Text style={styles.itemsize}>Pressure</Text>
            <Text style={styles.itemsize}>Humidity</Text>        
        </View>
    );
}
}

const styles = StyleSheet.create({
    content: {
        flex: 1,
        justifyContent: 'center',
        alignItems:'center'
    },
    city: {
        fontSize: 50,
        padding: 20
    },
    itemsize: {
        fontSize: 30,
        padding: 5
    }
})

export default Content;

and this is my upper component which is trying to get data and pass down.

import React, { Component } from 'react';
import Content from './Content';
import GetWeather  from './GetWeather';

class Home extends Component {
    constructor(props) {
        super(props);
        this._getData.bind(this);
        this._getData();
        this.state = {
            data: null,
        };

    }

    _getData = () => {
        GetWeather.getWeather().then( json => {
            console.log(json);
            this.setState({data: json});

        }); 

    };
    render() {

        return (
            <Content weather={this.state.data}/>
        );
    }
}

export default Home;

and last one is code that I wrote to get api data from openweathermap

function getLocation(lat, long) {
    return `${API_STEM}lat=${lat}&lon=${long}&appid=${APP_ID}`;

}
function getWeather() {
    return fetch(getLocation(LATTITUDE,LONGGITUDE))
    .then(response => response.json())
    .then(responseJson => { 
        return { main: responseJson.weather[0].main};})
    .catch(err =>console.log(err));
}

export default {getWeather: getWeather};

3 Answers 3

1

In your parent component, state never gets data and always remains null. When we want to fetch data from an API, we should use a react lifecycle method called componentDidMount(). So in your parent component, you should either call your _getdata function in componentDidMount or fetch your data in the lifecycle method, like below code which is a better way in my opinion. Also, never initially set your state to null. set it to an empty object.

import React, { Component } from 'react';
import Content from './Content';
import GetWeather  from './GetWeather';

class App extends Component {
    constructor(props) {
        super(props);
        
        this.state = {
            data: {},
        };

    }

    componentDidMount() {
        GetWeather.getWeather().then( json => {
            console.log(json);
            this.setState({data: json});

        });
    }
    
    
    render() {
        console.log(this.state.data);
        return (
            <Content weather={this.state.data}/>
        );
    }
}

export default App

and then in your child component, you should either use one of updating lifecycle methods (that has risks) or you can change your child component to functional component, for you don't need state.

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

function Content(props) {

    return (
        <View style={styles.content}>
            <Text style={styles.city}>City Name</Text>
            <Text style={styles.itemsize}>Weather {props.weather.main}</Text>
            <Text style={styles.itemsize}>Description</Text>
            <Text style={styles.itemsize}>Temperature Celsius</Text>
            <Text style={styles.itemsize}>Pressure</Text>
            <Text style={styles.itemsize}>Humidity</Text>        
        </View>
     )
}

const styles = StyleSheet.create({
    content: {
        flex: 1,
        justifyContent: 'center',
        alignItems:'center'
    },
    city: {
        fontSize: 50,
        padding: 20
    },
    itemsize: {
        fontSize: 30,
        padding: 5
    }
})

export default Content;

Sign up to request clarification or add additional context in comments.

Comments

0

The main problem is that this.state.data in the Home component is set after the Content component is created (after its constructor function is called).

This will generate a TypeError because this.props.weather is undefined and you are trying to access a property this.props.weather.main.

The easiest way to solve this will be to use the props object directly instead of adding those props to the state, here is an example:

<Text style={styles.itemsize}>Weather {this.props.weather}</Text>

Comments

0

Before the request finishes you already set this.state.data inside Content to null and it will not get updated when the component re-renders because the constructor only runs once on mount.

Setting state from props is an anti pattern and should be used only in rare situations.

Instead, read the weather data from this.props which will get updated once the parent component updates his state

You would also need to check if this.props.weather is null before you access .main inside this.props.weather

class Content extends Component {
  render() {
    const { weather } = this.props

    return (
      <View style={styles.content}>
        <Text style={styles.city}>City Name</Text>
        <Text style={styles.itemsize}>
          Weather {weather ? weather.main : null}
        </Text>
        <Text style={styles.itemsize}>Description</Text>
        <Text style={styles.itemsize}>Temperature Celsius</Text>
        <Text style={styles.itemsize}>Pressure</Text>
        <Text style={styles.itemsize}>Humidity</Text>
      </View>
    )
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.