Reputation: 1196
When I compile my files and run in console log I get this error
enter code here
Uncaught TypeError: Cannot read property 'nameOfCity' of null at App.render
They all "meet" at App component(I am using 'create-react-app' pack from facebook). I presume that it should load first Form Container and in it logic set initial state to empty and then Weather info data comes. Or am I wrong?
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
import {FormContainer} from './containers/FormContainer';
import WeatherInfo from './components/WeatherInfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Weather App</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<FormContainer label="Name of the city:"/>
<WeatherInfo
nameOfCity={this.state.nameOfCity}
weatherDescription={this.state.weatherDescription}
windSpeed={this.state.windSpeed}
temperature={this.state.temperature}
maxTemperature={this.state.maxTemperature}
minTemperature={this.state.minTemperature}
/>
</div>
);
}
}
export default App;
Form Container
import React, {Component} from 'react';
import SearchBar from '../components/SearchBar';
class FormContainer extends Component {
constructor(props) {
super(props);
this.state = {
cityName: '',
nameOfCity:'',
weatherDescription:'',
windSpeed:'',
temperature:'',
maxTemperature:'',
minTemperature:''
};
this.handleFormSubmit = this.handleFormSubmit.bind(this);
this.handleCityName = this.handleCityName.bind(this);
}
handleFormSubmit(e) {
e.preventDefault();
const SendForm = {
cityName: this.state.cityName
};
console.log(SendForm);
fetch(`http://api.openweathermap.org/data/2.5/forecast/weather?q=${SendForm.cityName}&units=metric&APPID=********`)
.then(res => res.json())
.then(results => {
this.setState({
nameOfCity: results.city.name,
weatherDescription: results.list[0].weather[0].description,
windSpeed: results.list[2].wind.speed,
temperature: results.list[0].main.temp,
maxTemperature: results.list[0].main.temp_max,
minTemperature: results.list[0].main.temp_min
});
});
}
handleCityName(value) {
this.setState({ cityName: value });
}
render() {
return (
<div>
<form onSubmit={this.handleFormSubmit}>
<label>{this.props.label}</label>
<SearchBar
name="CityName"
type="text"
value={this.state.cityName}
placeholder="search"
onChange={this.handleCityName}
/>
<button type="submit"
className=""
value='Submit'
placeholder="Search" />
</form>
</div>
);
}
}
export {FormContainer};
Search bar component
import React, {Component} from 'react';
const SearchBar = (props) => (
<div>
<label>{props.label}</label>
<input name={props.name} type={props.inputType} value={props.value} placeholder={props.placeholder} onChange={(e)=>props.onChange(e.target.value)}/>
</div>
);
export default SearchBar;
and Weather Info component
import React, {Component} from 'react';
const WeatherInfo = (props) => (
<div>
<ul>
<li>{props.nameOfCity}</li>
<li>{props.weatherDescription}</li>
<li>{props.windSpeed}</li>
<li>{props.temperature}</li>
<li>{props.maxTemperature}</li>
<li>{props.minTemperature}</li>
</ul>
</div>
);
export default WeatherInfo;
Upvotes: 0
Views: 692
Reputation: 71
These type of error occurs when you try to use attributes of non existing data. In this case this.state don't have value i.e. its null. So make sure your this.state have desired value by some manipulation as per your functionality.
Upvotes: 0
Reputation: 26
You're trying to read nameOfCity from this.state in App, but your App component does not hold state.
You can have FormContainer use context and render WeatherInfo as a child:
class FormContainer extends Component {
...
static childContextTypes = {
nameOfCity: React.PropTypes.string
}
getChildContext() {
return {
nameOfCity: this.state.nameOfCity
}
}
render: () {
...
</form>
{this.children}
}
}
App.jsx:
<FormContainer label="Name of the City:">
<WeatherInfo />
</FormContainer>
WeatherInfo.jsx:
class WeatherInfo extends React.Component {
static contextTypes = {
nameOfCity: React.PropTypes.string
}
render: () {
<div>
<ul>
<li>{this.context.nameOfCity}</li>
...
}
}
OR you can store state in App, and have FormContainer change App.state either by passing a prop, or by using context.
Upvotes: 1
Reputation: 104379
Issue is u r using this.state
in App component
, and in App component
u didn't define any state
, that's why it is throwing the error, can't read Cannot read property 'nameOfCity' of null
, because state
is null
. U need to define state
in App component
and then pass this state
values in props
and use those values in other component
.
Upvotes: 0
Reputation: 9185
The error is occurring at <WeatherInfo nameOfCity={this.state.nameOfCity}
because at this point you don't have nameOfCity
in the App
component state.
In your code, the nameOfCity
variable is inside FormContainer
component state. If you want to use it across the components, you should have the state at the App
component.
Upvotes: 1