Расположение макета похоже на дрожание, пока в React не загрузится результат / прогноз погоды для нового города. - PullRequest
0 голосов
/ 14 марта 2019

Я использую условный рендеринг для моего погодного приложения на github. Приложение работает нормально, но когда оно отображает результат для вновь введенного города, расположение макета похоже на дрожание, пока результат / прогноз погоды для нового города не будет загружен. Я полагаю, это вопрос дизайна. Может кто-нибудь проверить? Вот мое приложение:

import React, { Component } from 'react';
import Spinner from '../UI/Spinner';
import './App.css';
import {TweenLite, TimelineLite} from "gsap/TweenMax";

class App extends Component {
    state = {
        cityData: null,
        cityName: '',
        confirmedCityName: '',
        error: '',
        searchNameString: '',
        woeid: '',
        weatherData: '',
        weatherForecast: '',
        weatherIcon: null,
        loading: false
    }

    validate = () => {
        let isError = false;
        let error = '';

        if(this.state.cityName.length === 0){
              isError = true;
              error = 'Pls.enter a valid city name';
          } else {
              error = ''
          }
          this.setState({
            error,
            confirmedCityName: '',
          })
          return isError
    }

    submitHandler = (event) => {
        event.preventDefault();
        const err = this.validate();

        if(err === false) {
            const searchString = 'https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/search/?query=';
            const searchNameString = searchString.concat(this.state.cityName);
            this.setState({
                searchNameString
            })
            fetch(searchNameString)
                .then(response =>  {
                  console.log(response);
                  return response.json()
                })
                .then(data => {
                    if(data.length === 0) {
                        let error = 'You have entered invalid city name or name that not exist in our database of cities, pls.enter existent city name';
                        this.setState({
                            error,
                            confirmedCityName: ''
                        }) 
                    } else {
                        const woeid = data[0].woeid;
                        this.setState({
                            loading: true,
                            confirmedCityName: this.state.cityName,
                            cityData: data,
                            woeid
                        })
                        const searchString = 'https://cors-anywhere.herokuapp.com/https://www.metaweather.com/api/location/';
                        const searchWoeidString = searchString.concat(`${this.state.woeid}/`);
                        return fetch(searchWoeidString)
                    }
                })
                .then(response => {
                    return response.json()
                    }              
                )
                .then(data => {
                    const today = data.consolidated_weather[0];
                    const country = data.parent.title;
                    const weatherForecast = 
                    <div>Today in <strong>{this.state.cityName}, {country}</strong> weather will be with <strong>{today.weather_state_name}</strong>, 
                        min temperature <strong>{parseInt(today.min_temp)}°C</strong>,  
                        max temperature <strong>{parseInt(today.max_temp)}°C</strong>,
                        and humidity will be <strong>{today.humidity}%</strong></div>;
                    const weatherIcon = `https://www.metaweather.com/static/img/weather/png/${today.weather_state_abbr}.png`;                    
                    this.setState({
                        loading: false, 
                        weatherData: data,
                        weatherForecast,
                        weatherIcon,
                        cityName: ''
                    })
                })
                .catch(error => console.log(error));

                this.setState({
                    weatherData: '',
                    weatherForecast: '',
                })
        }
    }

    nameChangeHandler = input => event => {
        this.setState({
          [input]: event.target.value
        })
    }

    componentDidMount(){
        let animation = new TimelineLite();
        TweenLite.ticker.useRAF(false);
        TweenLite.lagSmoothing(0);

        const spinningPic = document.getElementById('spinning-pic');
        animation.to(spinningPic, 1, {rotation: "+=360", transformOrigin:"center center"});
    }

    render() {
        let weatherOutput = null;
        if(this.state.loading) {
            weatherOutput = (
                <React.Fragment>
                    {/*Spinner*/}
                    <Spinner />
                    {/*Content-forecast-empty*/}
                    <div className="container-fluid content-forecast">
                          <div className="container"> 
                              <p className="forecast"></p>
                          </div>
                    </div>
                </React.Fragment>
            )
        } else {
            weatherOutput = (
              <React.Fragment>
                  {/*Weather Icon got from server*/}
                  <div className={"container-fluid content" + (this.state.weatherIcon !== null ? ' visible' : ' nonvisible')}>
                      <div className="container"> 
                          <div className="img-wrapper"><img src={this.state.weatherIcon} alt=""/></div>
                      </div>
                  </div>
                  {/*Forecast string empty*/}
                  <div className="container-fluid content-forecast">
                      <div className="container"> 
                          <div className="forecast">{this.state.weatherForecast}</div>
                      </div>
                  </div>
              </React.Fragment>
            )
        }
        return (
            <div className="App">
                <div className="container-fluid title-background">
                    <div className="container">
                        <h1>Weather forecast app</h1>
                    </div>
                </div>
                <div className="container-fluid header-background">
                    <div className="container">
                        <h3>Search Weather data for {this.state.confirmedCityName}</h3>
                        <form>
                          <input 
                              type="text"
                              placeholder="Pls.enter city name"
                              value={this.state.cityName}
                              onChange={this.nameChangeHandler('cityName')}
                          />
                          <button
                              type="submit"
                              onClick={this.submitHandler}
                          >
                              ENTER
                          </button>
                        </form>
                        <p className="error-message">{this.state.error}</p>
                    </div>
                </div>
                <div className="container-fluid">
                    {/*Opening pic*/}  
                    <div className="container">
                        <div className="spinning-pic-wrapper"><img id="spinning-pic" src="https://www.metaweather.com/static/img/weather/png/c.png" 
                        className={(this.state.weatherIcon !== null || this.state.loading === true ? 'nonVisible' : '')} alt="sun"/></div>  
                    </div>
                    {/*Weather Icon got from server, Forecast string empty*/}
                    <div className="weatherOutputWrapper">
                      {weatherOutput} 
                    </div>
                </div> 
                <div className="container-fluid footer-background">
                    <div className="container">
                        <h3>Getting today's weather forecast</h3>
                        <div className="icon-wrapper"><img src="https://www.metaweather.com/static/img/weather/lc.svg" alt="weather Icon"/></div>
                    </div>
                </div>
            </div>
        );
    }
}

export default App;

Вот файл CSS:

/* ------------------------------------ */
input {
    outline: none;
    border: none;
    padding-top: 10px;
    padding-bottom: 10px;
    padding-left: 15px;
    margin-right: 10px;
    font-size: 18px;
    border-radius: 20px;
}

/* ------------------------------------ */
button {
    outline: none;
    border: solid 2px #fff;
    color: #fff;
    border-radius: 20px;
    padding-top: 10px;
    padding-bottom: 10px;
    padding-left: 15px;
    padding-right: 15px;
    margin-bottom: 15px;
    background: transparent;
    display: inline-block;
    text-align: center;
    transition: background-color .3s ease-in-out, border .3s ease-in-out;
}

button:hover, button:focus {
    cursor: pointer;
    background-color: #00697D;
    border: solid 2px transparent;
}

img {
    max-width: 100%;
    height: auto;
    max-height: 450px;
    margin-top: 25px;
    display: inline-block;
}

h1 {
    font-family: OswaldLight;
    font-size: 25px;
    padding-top: 10px;
    padding-bottom: 10px;
}

form {
    text-align: center;
}

.container-fluid {
    padding-right: 0px;
    padding-left: 0px;
    margin-right: auto;
    margin-left: auto;
}

.container {
    padding-right: 0px;
    padding-left: 0px;
    margin-right: auto;
    margin-left: auto;
    max-width: 100%;
}

.title-background {
    background-color: #353432;
    border-bottom: 1px solid #666;
}

.title-background h1 {
    color: #fff;
}

.header-background {
    background-color: #4E4D4A;
}

.header-background h3 {
    font-size: 35px;
    padding-top: 30px;
    padding-bottom: 10px;
    text-align: center;
    background-color: #4E4D4A;
    color: #FF8C18;
}

.header-background p {
    text-align: center;
}

.content {
    text-align: center;
    display: none;
}

.content-forecast {
    height: 45px;
    padding-top: 15px;
    padding-bottom: 15px;
    margin-top: 40px;
    background-color: #D3D3D3;
    text-align: center;
}

.weather-forecast {
    background-color: #4E4D4A;
}

.error-message {
    color: #ecf0f1;
    height: 20px;
    padding-bottom: 35px;
}

.spinning-pic-wrapper {
    text-align: center;
}

#spinningPic {
    transform-origin: 50% 50%;
}

.nonVisible {
    display: none;
}

.visible {
    display: block;
}

.footer-background {
    background-color: #353432;
    border-top: 1px solid #666;
    font-family: OswaldLight;
    font-size: 18px;
    padding-top: 10px;
    padding-bottom: 10px;
    text-align: right;
}

.footer-background h3 {
    color: #fff;
    display: inline-block;
    margin-right: 10px;
}

.icon-wrapper {
    display: inline-block;
    height: 25px;
    width: 25px;
}

.icon-wrapper img{
    margin-top: 0px;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...