Weather App React 点击三下更新状态和传递 props
Weather App React taking three clicks to update state and pass props
对于我的天气应用程序,目标是让用户输入经纬度并查看八天的预报。它有效,但我必须点击提交三次才能正确获取数据。
目前正在努力确保 API 仅在用户单击提交时调用。不确定我是否需要 onclick 和 onsubmit,但这似乎是 API fetch 不会在用户每次键入内容时调用的唯一方法。
weatherView:用户输入信息并将其作为道具发送的地方。
import React, { Component } from 'react';
import { WeatherCard } from './weatherCard';
export class WeatherView extends Component {
constructor(props) {
super(props);
this.state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onClick = this.onClick.bind(this);
}
onChangeLat = (e) => {
this.setState({
valueLat: e.target.value,
check: false
});
}
onChangeLong = (e) => {
this.setState({
valueLong: e.target.value,
check: false
});
}
onSubmit = (e) => {
e.preventDefault()
if (this.state.valueLat === " " || this.state.valueLong === " ") {
alert("You must enter something");
}
this.setState({
lat: this.state.valueLat,
latLongBool: true,
long: this.state.valueLong
})
console.log("lat and long stored")
}
onClick = (e) => {
this.setState({
latLong: this.state.lat + "," + this.state.long,
check: true
})
console.log("Prop to send " + this.state.latLong)
}
shouldComponentUpdate(nextState) {
console.log('shouldComponentUpdate activated 1');
return this.state.latLong !== nextState.latLong;
}
render() {
return(
<div>
<h1>Welcome to the Weather App!</h1>
<form onSubmit={this.onSubmit}>
Enter the Latitude in decimal format: <input type="text" name="lat" value={this.state.valueLat} onChange={this.onChangeLat}/>
<br/>
Enter the Longitude in decimal format: <input type="text" name="long" value={this.state.valueLong} onChange={this.onChangeLong}/>
<br/>
<button onClick={this.onClick} >Submit</button>
</form>
<WeatherCard latLong = {this.state.latLong} check={this.state.check}/>
</div>
)
}
}
天气卡:
import React, { Component } from 'react';
import ReactAnimatedWeather from 'react-animated-weather';
const defaults = [
{
icon: 'CLEAR_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLEAR_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLOUDY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'RAIN',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SLEET',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SNOW',
color: 'white',
size: 175,
animate: true
},
{
icon: 'WIND',
color: 'white',
size: 175,
animate: true
},
{
icon: 'FOG',
color: 'white',
size: 175,
animate: true
}
];
function iconConverter(arg){
switch (arg) {
case 'clear-day': return 0;
break;
case 'clear-night': return 1;
break;
case 'partly-cloudy-day': return 2;
break;
case 'partly-cloudy-night': return 3;
break;
case 'cloudy': return 4;
break;
case 'rain': return 5;
break;
case 'sleet': return 6;
break;
case 'snow': return 7;
break;
case 'wind': return 8;
break;
case 'fog': return 9;
break;
}
}
const WCard = ({day, high, low, humidity, summary, sunrise, sunset, windspeed, time, rainProb, icon}) =>{
return (
<div>
<p>{time}</p>
<div id='wCardIcon'>
<ReactAnimatedWeather
icon={defaults[iconConverter(icon)].icon}
color={defaults[iconConverter(icon)].color}
size={defaults[iconConverter(icon)].size}
animate={defaults[iconConverter(icon)].animate}
/>
<div>
<p>⇧ {high}℉</p>
<p>{low}℉ ⇩</p>
</div>
</div>
<p id="wCardSum">{summary}</p>
<p>Humidity: {humidity}%</p>
<p>Wind speed: {windspeed}mph</p>
<p>Sunrise: {sunrise}</p>
<p>Sunset: {sunset}</p>
<p>Chance of rain: {rainProb}%</p>
</div>
)};
// const weatherAPI = 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/34.0522,-118.2437';
const weatherAPI = 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/';
export class WeatherCard extends Component {
constructor(props) {
super(props)
this.state = {
requestFailed: false,
info: '',
latLongSubmitted: false,
latLongValue: this.props.latLong,
weatherAPI: 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/'
}
}
componentWillReceiveProps(nextProps){
if (this.props.check) {
console.log("Receive Props activated")
console.log("Prop: " + this.props.latLong)
console.log("Value for API" + this.latLongValue)
if(this.props.latLong !== nextProps.latLong) {
this.setState({
latLongValue: nextProps.latLong,
latLongSubmitted: true
})
console.log(this.latLongValue)
}
console.log('componentDidMount is running')
fetch(this.state.weatherAPI + this.state.latLongValue)
.then(response => {
if (!response.ok) {
throw Error("Network request failed")
}
return response;
})
.then(data => data.json())
.then(data => {
this.setState({
info: data
})
console.log(data)
}, () => {
this.setState({
requestFailed: true
})
})
}
}
shouldComponentUpdate(nextProps) {
console.log('shouldComponentUpdate activated 2');
return this.state.latLongValue !== nextProps.latLongValue;
}
timeDateConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var formattedDate = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
return formattedDate
}
removeMilitary(hours){
if (hours > 0 && hours <= 12) {
hours = "" + hours;
} else if (hours > 12) {
hours = "" + (hours - 12);
} else if (hours === 0) {
hours= "12";
}
return hours;
}
timeConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var hours = d.getHours();
if (hours>=12){ //Adding endings
var suffix = "P.M.";}
else{
suffix = "A.M.";}
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
hours = this.removeMilitary(hours);
var formattedTime = hours + ":" + minutes + " " + suffix;
return formattedTime;
}
render() {
if (!this.state.latLongSubmitted) return <p>Waiting for coordinates... try 34.0522, -118.2437</p>
// if (this.state.requestFailed) return <p>Failed</p>
if (!this.state.info) return <p>Loading...</p>
return(
<div>
<h1>The current temperature in {this.state.info.timezone} is: {this.state.info.currently.apparentTemperature}℉.</h1>
<h1>The 8 day forecast for {this.state.info.timezone}:</h1>
<ul>
{this.state.info.daily.data.map((day, id) =>
<div key={{id}>{day}} id="weatherCard">
<WCard time={this.timeDateConverter(day.time)}
high={day.temperatureHigh}
low={day.temperatureLow}
summary={day.summary}
icon={day.icon}
humidity={day.humidity}
sunrise={this.timeConverter(day.sunriseTime)}
sunset={this.timeConverter(day.sunsetTime)}
rainProb={day.precipProbability}
windspeed={day.windSpeed}
/>
</div>
)}
</ul>
<a href="https://darksky.net/poweredby/">Powered by DarkSky</a>
</div>
)
}
}
好的..这里有很多要解决的问题,但让我们从问题的核心开始:
在 WeatherCard 里面你有这个:
componentWillReceiveProps(nextProps){
if (this.props.check)
当然这不会第一次触发,因为你正在检查旧道具。
componentWillReceiveProps(nextProps){
if (nextProps.check) {
神奇!有效。
好的,但是..让我们解决一些其他问题。
1) 您已经在使用 class 属性 (method = e =>
),因此您可以减少很多麻烦:
整个街区:
class WeatherView extends React.Component {
constructor(props) {
super(props);
this.state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onClick = this.onClick.bind(this);
}
可以替换为:
class WeatherView extends React.Component {
state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
如果你不使用箭头函数,你只需要绑定东西,这是一回事。
2) 您不需要输入值的重复状态以及这些输入值变成的东西。你可以完全放弃state.valueLong
和state.valueLong
..你只需要state.lat
和state.long
。
考虑到这一点,您可以完全放弃 <form>
和 onSubmit
。
突发: 我的电脑快没电了。回家后我必须完成这个答案,但我会写更多。
与此同时,您可以在此处看到大部分已修复的版本 https://stackblitz.com/edit/react-hrfmuh?file=WeatherView.js api 调用不起作用,但会像您期望的那样触发
我会从三个方面来解决这个问题。我已经重写了你的一些组件。我删除了不必要的状态道具和代码。您可以复制并粘贴然后尝试分析代码。如果你有任何问题,我在这里
WeatherApp.js
import React, { Component } from 'react';
import { WeatherForm } from './WeatherForm';
import { WeatherCard } from './WeatherCard';
export class WeatherApp extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0,
long: 0,
}
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit = (lat, long) => {
this.setState({
lat,
long
});
}
render() {
return(
<div>
<WeatherForm onSubmit={this.onSubmit}/>
<WeatherCard lat={this.state.lat} long={this.state.long}/>
</div>
)
}
}
WeatherForm.js
import React, { Component } from 'react';
export class WeatherForm extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0,
long: 0,
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChangeLat = (e) => {
let value = e.target.value;
if(!isNaN(value) ){
this.setState({
lat: e.target.value
});
}
}
onChangeLong = (e) => {
let value = e.target.value;
if(!isNaN(value) ){
this.setState({
long: e.target.value
});
}
}
onSubmit = (e) => {
e.preventDefault();
if (this.state.lat.length == 0 || this.state.long.length == 0) {
alert("You must enter something");
}else{
this.props.onSubmit(this.state.lat, this.state.long)
}
}
render() {
return(
<div>
<h1>Welcome to the Weather App!</h1>
<form onSubmit={this.onSubmit}>
Enter the Latitude in decimal format: <input type="text" name="lat" value={this.state.lat} onChange={this.onChangeLat}/>
<br/>
Enter the Longitude in decimal format: <input type="text" name="long" value={this.state.long} onChange={this.onChangeLong}/>
<br/>
<button >Submit</button>
</form>
</div>
)
}
}
WeatherCard.js
import React, { Component } from 'react';
import ReactAnimatedWeather from 'react-animated-weather';
const defaults = [
{
icon: 'CLEAR_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLEAR_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLOUDY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'RAIN',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SLEET',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SNOW',
color: 'white',
size: 175,
animate: true
},
{
icon: 'WIND',
color: 'white',
size: 175,
animate: true
},
{
icon: 'FOG',
color: 'white',
size: 175,
animate: true
}
];
function iconConverter(arg){
switch (arg) {
case 'clear-day': return 0;
break;
case 'clear-night': return 1;
break;
case 'partly-cloudy-day': return 2;
break;
case 'partly-cloudy-night': return 3;
break;
case 'cloudy': return 4;
break;
case 'rain': return 5;
break;
case 'sleet': return 6;
break;
case 'snow': return 7;
break;
case 'wind': return 8;
break;
case 'fog': return 9;
break;
}
}
const WCard = ({day, high, low, humidity, summary, sunrise, sunset, windspeed, time, rainProb, icon}) =>{
return (
<div>
<p>{time}</p>
<div id='wCardIcon'>
<ReactAnimatedWeather
icon={defaults[iconConverter(icon)].icon}
color={defaults[iconConverter(icon)].color}
size={defaults[iconConverter(icon)].size}
animate={defaults[iconConverter(icon)].animate}
/>
<div>
<p>⇧ {high}℉</p>
<p>{low}℉ ⇩</p>
</div>
</div>
<p id="wCardSum">{summary}</p>
<p>Humidity: {humidity}%</p>
<p>Wind speed: {windspeed}mph</p>
<p>Sunrise: {sunrise}</p>
<p>Sunset: {sunset}</p>
<p>Chance of rain: {rainProb}%</p>
</div>
)};
export class WeatherCard extends Component {
constructor(props) {
super(props)
this.state = {
requestFailed: false,
info: undefined,
latLongValue: this.props.latLong
}
}
componentDidMount(){
this.fetchData(this.props.lat, this.props.long);
}
componentWillReceiveProps(nextProps){
this.fetchData(nextProps.lat, nextProps.long);
}
timeDateConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var formattedDate = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
return formattedDate
}
removeMilitary(hours){
if (hours > 0 && hours <= 12) {
hours = "" + hours;
} else if (hours > 12) {
hours = "" + (hours - 12);
} else if (hours === 0) {
hours= "12";
}
return hours;
}
timeConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var hours = d.getHours();
if (hours>=12){ //Adding endings
var suffix = "P.M.";}
else{
suffix = "A.M.";}
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
hours = this.removeMilitary(hours);
var formattedTime = hours + ":" + minutes + " " + suffix;
return formattedTime;
}
fetchData(lat, long){
const weatherRequest = `https://api.darksky.net/forecast/fbdca57e2ef5b4ac0f12e3d3779f090e/${lat},${long}`;
console.log(weatherRequest);
fetch(weatherRequest).then( data => data.json() ).then( data => {
this.setState({
info: data,
requestFailed: true
});
}, () => {
this.setState({
requestFailed: true
})
})
}
render() {
return(
this.state.info ? (<div>
<h1>The current temperature in {this.state.info.timezone} is: {this.state.info.currently.apparentTemperature}</h1>
<h1>The 8 day forecast for {this.state.info.timezone}:</h1>
<ul>
{this.state.info.daily.data.map((day, id) =>
<div key={'_' + Math.random().toString(36).substr(2, 9)} id="weatherCard">
<WCard time={this.timeDateConverter(day.time)}
high={day.temperatureHigh}
low={day.temperatureLow}
summary={day.summary}
icon={day.icon}
humidity={day.humidity}
sunrise={this.timeConverter(day.sunriseTime)}
sunset={this.timeConverter(day.sunsetTime)}
rainProb={day.precipProbability}
windspeed={day.windSpeed}
/>
</div>
)}
</ul>
<a href="https://darksky.net/poweredby/">Powered by DarkSky</a>
</div>
) : <div>Loading</div>
)
}
}
将属性 type="submit" 添加到您的按钮
<button type="submit"></button>
对于我的天气应用程序,目标是让用户输入经纬度并查看八天的预报。它有效,但我必须点击提交三次才能正确获取数据。
目前正在努力确保 API 仅在用户单击提交时调用。不确定我是否需要 onclick 和 onsubmit,但这似乎是 API fetch 不会在用户每次键入内容时调用的唯一方法。
weatherView:用户输入信息并将其作为道具发送的地方。
import React, { Component } from 'react';
import { WeatherCard } from './weatherCard';
export class WeatherView extends Component {
constructor(props) {
super(props);
this.state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onClick = this.onClick.bind(this);
}
onChangeLat = (e) => {
this.setState({
valueLat: e.target.value,
check: false
});
}
onChangeLong = (e) => {
this.setState({
valueLong: e.target.value,
check: false
});
}
onSubmit = (e) => {
e.preventDefault()
if (this.state.valueLat === " " || this.state.valueLong === " ") {
alert("You must enter something");
}
this.setState({
lat: this.state.valueLat,
latLongBool: true,
long: this.state.valueLong
})
console.log("lat and long stored")
}
onClick = (e) => {
this.setState({
latLong: this.state.lat + "," + this.state.long,
check: true
})
console.log("Prop to send " + this.state.latLong)
}
shouldComponentUpdate(nextState) {
console.log('shouldComponentUpdate activated 1');
return this.state.latLong !== nextState.latLong;
}
render() {
return(
<div>
<h1>Welcome to the Weather App!</h1>
<form onSubmit={this.onSubmit}>
Enter the Latitude in decimal format: <input type="text" name="lat" value={this.state.valueLat} onChange={this.onChangeLat}/>
<br/>
Enter the Longitude in decimal format: <input type="text" name="long" value={this.state.valueLong} onChange={this.onChangeLong}/>
<br/>
<button onClick={this.onClick} >Submit</button>
</form>
<WeatherCard latLong = {this.state.latLong} check={this.state.check}/>
</div>
)
}
}
天气卡:
import React, { Component } from 'react';
import ReactAnimatedWeather from 'react-animated-weather';
const defaults = [
{
icon: 'CLEAR_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLEAR_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLOUDY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'RAIN',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SLEET',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SNOW',
color: 'white',
size: 175,
animate: true
},
{
icon: 'WIND',
color: 'white',
size: 175,
animate: true
},
{
icon: 'FOG',
color: 'white',
size: 175,
animate: true
}
];
function iconConverter(arg){
switch (arg) {
case 'clear-day': return 0;
break;
case 'clear-night': return 1;
break;
case 'partly-cloudy-day': return 2;
break;
case 'partly-cloudy-night': return 3;
break;
case 'cloudy': return 4;
break;
case 'rain': return 5;
break;
case 'sleet': return 6;
break;
case 'snow': return 7;
break;
case 'wind': return 8;
break;
case 'fog': return 9;
break;
}
}
const WCard = ({day, high, low, humidity, summary, sunrise, sunset, windspeed, time, rainProb, icon}) =>{
return (
<div>
<p>{time}</p>
<div id='wCardIcon'>
<ReactAnimatedWeather
icon={defaults[iconConverter(icon)].icon}
color={defaults[iconConverter(icon)].color}
size={defaults[iconConverter(icon)].size}
animate={defaults[iconConverter(icon)].animate}
/>
<div>
<p>⇧ {high}℉</p>
<p>{low}℉ ⇩</p>
</div>
</div>
<p id="wCardSum">{summary}</p>
<p>Humidity: {humidity}%</p>
<p>Wind speed: {windspeed}mph</p>
<p>Sunrise: {sunrise}</p>
<p>Sunset: {sunset}</p>
<p>Chance of rain: {rainProb}%</p>
</div>
)};
// const weatherAPI = 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/34.0522,-118.2437';
const weatherAPI = 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/';
export class WeatherCard extends Component {
constructor(props) {
super(props)
this.state = {
requestFailed: false,
info: '',
latLongSubmitted: false,
latLongValue: this.props.latLong,
weatherAPI: 'https://api.darksky.net/forecast/926bb6de03f1ae8575d48aaeb2fc9b83/'
}
}
componentWillReceiveProps(nextProps){
if (this.props.check) {
console.log("Receive Props activated")
console.log("Prop: " + this.props.latLong)
console.log("Value for API" + this.latLongValue)
if(this.props.latLong !== nextProps.latLong) {
this.setState({
latLongValue: nextProps.latLong,
latLongSubmitted: true
})
console.log(this.latLongValue)
}
console.log('componentDidMount is running')
fetch(this.state.weatherAPI + this.state.latLongValue)
.then(response => {
if (!response.ok) {
throw Error("Network request failed")
}
return response;
})
.then(data => data.json())
.then(data => {
this.setState({
info: data
})
console.log(data)
}, () => {
this.setState({
requestFailed: true
})
})
}
}
shouldComponentUpdate(nextProps) {
console.log('shouldComponentUpdate activated 2');
return this.state.latLongValue !== nextProps.latLongValue;
}
timeDateConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var formattedDate = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
return formattedDate
}
removeMilitary(hours){
if (hours > 0 && hours <= 12) {
hours = "" + hours;
} else if (hours > 12) {
hours = "" + (hours - 12);
} else if (hours === 0) {
hours= "12";
}
return hours;
}
timeConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var hours = d.getHours();
if (hours>=12){ //Adding endings
var suffix = "P.M.";}
else{
suffix = "A.M.";}
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
hours = this.removeMilitary(hours);
var formattedTime = hours + ":" + minutes + " " + suffix;
return formattedTime;
}
render() {
if (!this.state.latLongSubmitted) return <p>Waiting for coordinates... try 34.0522, -118.2437</p>
// if (this.state.requestFailed) return <p>Failed</p>
if (!this.state.info) return <p>Loading...</p>
return(
<div>
<h1>The current temperature in {this.state.info.timezone} is: {this.state.info.currently.apparentTemperature}℉.</h1>
<h1>The 8 day forecast for {this.state.info.timezone}:</h1>
<ul>
{this.state.info.daily.data.map((day, id) =>
<div key={{id}>{day}} id="weatherCard">
<WCard time={this.timeDateConverter(day.time)}
high={day.temperatureHigh}
low={day.temperatureLow}
summary={day.summary}
icon={day.icon}
humidity={day.humidity}
sunrise={this.timeConverter(day.sunriseTime)}
sunset={this.timeConverter(day.sunsetTime)}
rainProb={day.precipProbability}
windspeed={day.windSpeed}
/>
</div>
)}
</ul>
<a href="https://darksky.net/poweredby/">Powered by DarkSky</a>
</div>
)
}
}
好的..这里有很多要解决的问题,但让我们从问题的核心开始:
在 WeatherCard 里面你有这个:
componentWillReceiveProps(nextProps){
if (this.props.check)
当然这不会第一次触发,因为你正在检查旧道具。
componentWillReceiveProps(nextProps){
if (nextProps.check) {
神奇!有效。
好的,但是..让我们解决一些其他问题。
1) 您已经在使用 class 属性 (method = e =>
),因此您可以减少很多麻烦:
整个街区:
class WeatherView extends React.Component {
constructor(props) {
super(props);
this.state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.onClick = this.onClick.bind(this);
}
可以替换为:
class WeatherView extends React.Component {
state = {
lat: "",
long: "",
valueLat: "",
valueLong: "",
check: false,
latLongBool: false,
latLong: ""
}
如果你不使用箭头函数,你只需要绑定东西,这是一回事。
2) 您不需要输入值的重复状态以及这些输入值变成的东西。你可以完全放弃state.valueLong
和state.valueLong
..你只需要state.lat
和state.long
。
考虑到这一点,您可以完全放弃 <form>
和 onSubmit
。
突发: 我的电脑快没电了。回家后我必须完成这个答案,但我会写更多。
与此同时,您可以在此处看到大部分已修复的版本 https://stackblitz.com/edit/react-hrfmuh?file=WeatherView.js api 调用不起作用,但会像您期望的那样触发
我会从三个方面来解决这个问题。我已经重写了你的一些组件。我删除了不必要的状态道具和代码。您可以复制并粘贴然后尝试分析代码。如果你有任何问题,我在这里
WeatherApp.js
import React, { Component } from 'react';
import { WeatherForm } from './WeatherForm';
import { WeatherCard } from './WeatherCard';
export class WeatherApp extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0,
long: 0,
}
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit = (lat, long) => {
this.setState({
lat,
long
});
}
render() {
return(
<div>
<WeatherForm onSubmit={this.onSubmit}/>
<WeatherCard lat={this.state.lat} long={this.state.long}/>
</div>
)
}
}
WeatherForm.js
import React, { Component } from 'react';
export class WeatherForm extends Component {
constructor(props) {
super(props);
this.state = {
lat: 0,
long: 0,
}
this.onChangeLat = this.onChangeLat.bind(this);
this.onChangeLong = this.onChangeLong.bind(this);
this.onSubmit = this.onSubmit.bind(this);
}
onChangeLat = (e) => {
let value = e.target.value;
if(!isNaN(value) ){
this.setState({
lat: e.target.value
});
}
}
onChangeLong = (e) => {
let value = e.target.value;
if(!isNaN(value) ){
this.setState({
long: e.target.value
});
}
}
onSubmit = (e) => {
e.preventDefault();
if (this.state.lat.length == 0 || this.state.long.length == 0) {
alert("You must enter something");
}else{
this.props.onSubmit(this.state.lat, this.state.long)
}
}
render() {
return(
<div>
<h1>Welcome to the Weather App!</h1>
<form onSubmit={this.onSubmit}>
Enter the Latitude in decimal format: <input type="text" name="lat" value={this.state.lat} onChange={this.onChangeLat}/>
<br/>
Enter the Longitude in decimal format: <input type="text" name="long" value={this.state.long} onChange={this.onChangeLong}/>
<br/>
<button >Submit</button>
</form>
</div>
)
}
}
WeatherCard.js
import React, { Component } from 'react';
import ReactAnimatedWeather from 'react-animated-weather';
const defaults = [
{
icon: 'CLEAR_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLEAR_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_DAY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'PARTLY_CLOUDY_NIGHT',
color: 'white',
size: 175,
animate: true
},
{
icon: 'CLOUDY',
color: 'white',
size: 175,
animate: true
},
{
icon: 'RAIN',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SLEET',
color: 'white',
size: 175,
animate: true
},
{
icon: 'SNOW',
color: 'white',
size: 175,
animate: true
},
{
icon: 'WIND',
color: 'white',
size: 175,
animate: true
},
{
icon: 'FOG',
color: 'white',
size: 175,
animate: true
}
];
function iconConverter(arg){
switch (arg) {
case 'clear-day': return 0;
break;
case 'clear-night': return 1;
break;
case 'partly-cloudy-day': return 2;
break;
case 'partly-cloudy-night': return 3;
break;
case 'cloudy': return 4;
break;
case 'rain': return 5;
break;
case 'sleet': return 6;
break;
case 'snow': return 7;
break;
case 'wind': return 8;
break;
case 'fog': return 9;
break;
}
}
const WCard = ({day, high, low, humidity, summary, sunrise, sunset, windspeed, time, rainProb, icon}) =>{
return (
<div>
<p>{time}</p>
<div id='wCardIcon'>
<ReactAnimatedWeather
icon={defaults[iconConverter(icon)].icon}
color={defaults[iconConverter(icon)].color}
size={defaults[iconConverter(icon)].size}
animate={defaults[iconConverter(icon)].animate}
/>
<div>
<p>⇧ {high}℉</p>
<p>{low}℉ ⇩</p>
</div>
</div>
<p id="wCardSum">{summary}</p>
<p>Humidity: {humidity}%</p>
<p>Wind speed: {windspeed}mph</p>
<p>Sunrise: {sunrise}</p>
<p>Sunset: {sunset}</p>
<p>Chance of rain: {rainProb}%</p>
</div>
)};
export class WeatherCard extends Component {
constructor(props) {
super(props)
this.state = {
requestFailed: false,
info: undefined,
latLongValue: this.props.latLong
}
}
componentDidMount(){
this.fetchData(this.props.lat, this.props.long);
}
componentWillReceiveProps(nextProps){
this.fetchData(nextProps.lat, nextProps.long);
}
timeDateConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var formattedDate = (d.getMonth() + 1) + "/" + d.getDate() + "/" + d.getFullYear();
return formattedDate
}
removeMilitary(hours){
if (hours > 0 && hours <= 12) {
hours = "" + hours;
} else if (hours > 12) {
hours = "" + (hours - 12);
} else if (hours === 0) {
hours= "12";
}
return hours;
}
timeConverter(tempTime) {
var time = tempTime *1000;
var d = new Date(time);
var hours = d.getHours();
if (hours>=12){ //Adding endings
var suffix = "P.M.";}
else{
suffix = "A.M.";}
var minutes = (d.getMinutes() < 10) ? "0" + d.getMinutes() : d.getMinutes();
hours = this.removeMilitary(hours);
var formattedTime = hours + ":" + minutes + " " + suffix;
return formattedTime;
}
fetchData(lat, long){
const weatherRequest = `https://api.darksky.net/forecast/fbdca57e2ef5b4ac0f12e3d3779f090e/${lat},${long}`;
console.log(weatherRequest);
fetch(weatherRequest).then( data => data.json() ).then( data => {
this.setState({
info: data,
requestFailed: true
});
}, () => {
this.setState({
requestFailed: true
})
})
}
render() {
return(
this.state.info ? (<div>
<h1>The current temperature in {this.state.info.timezone} is: {this.state.info.currently.apparentTemperature}</h1>
<h1>The 8 day forecast for {this.state.info.timezone}:</h1>
<ul>
{this.state.info.daily.data.map((day, id) =>
<div key={'_' + Math.random().toString(36).substr(2, 9)} id="weatherCard">
<WCard time={this.timeDateConverter(day.time)}
high={day.temperatureHigh}
low={day.temperatureLow}
summary={day.summary}
icon={day.icon}
humidity={day.humidity}
sunrise={this.timeConverter(day.sunriseTime)}
sunset={this.timeConverter(day.sunsetTime)}
rainProb={day.precipProbability}
windspeed={day.windSpeed}
/>
</div>
)}
</ul>
<a href="https://darksky.net/poweredby/">Powered by DarkSky</a>
</div>
) : <div>Loading</div>
)
}
}
将属性 type="submit" 添加到您的按钮
<button type="submit"></button>