npm ๋ฆฌ์กํธ ๋ก๋ฉ์คํผ๋
https://www.npmjs.com/package/react-spinners
react-spinners
A collection of react loading spinners. Latest version: 0.13.7, last published: 7 days ago. Start using react-spinners in your project by running `npm i react-spinners`. There are 714 other projects in the npm registry using react-spinners.
www.npmjs.com
npm install --save react-spinners
Example
import { useState, CSSProperties } from "react";
import ClipLoader from "react-spinners/ClipLoader";
const override: CSSProperties = {
display: "block",
margin: "0 auto",
borderColor: "red",
};
function App() {
let [loading, setLoading] = useState(true);
let [color, setColor] = useState("#ffffff");
return (
<div className="sweet-loading">
<button onClick={() => setLoading(!loading)}>Toggle Loader</button>
<input value={color} onChange={(input) => setColor(input.target.value)} placeholder="Color of the loader" />
<ClipLoader
color={color}
loading={loading}
cssOverride={override}
size={150}
aria-label="Loading Spinner"
data-testid="loader"
/>
</div>
);
}
export default App;
๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ฌ ๊ทธ๋๋ก~ ํ๋ก์ ํธ์ ๋ณต๋ถํด๋ณธ๋ค.
import './App.css';
import { useEffect, useState } from 'react';
import WeatherBox from "./component/WaetherBox";
import WeatherButton from "./component/WeatherButton";
import ClipLoader from "react-spinners/ClipLoader";
import 'bootstrap/dist/css/bootstrap.min.css';
//1. ์ฑ์ด ์คํ๋์๋ง์ ํ์ฌ ์์น ๊ธฐ๋ฐ์ ๋ ์จ๊ฐ ๋ณด์ธ๋ค.
//2. ๋ ์จ ์ ๋ณด์๋ ๋์, ์ญ์จ, ํ์จ ๋ ์จ ์ํ
//3. 5๊ฐ์ ๋ฒํผ์ด ์๋ค (1๊ฐ๋ ํ์ฌ ์์น, 4๊ฐ๋ ๋ค๋ฅธ ๋์)
//4. ๋ก๋ฉ ์คํผ๋ ๊ธฐ๋ฅ ์ถ๊ฐ
function App() {
const [userWeather, setUserWeather] = useState(null);
const [city, setCity] = useState("Your Weather");
const cities = ['Your Weather', 'new york', 'toronto', 'paris', 'rondon'];
let [loading, setLoading] = useState(true);
let [color, setColor] = useState("#ffffff");
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
getWeatherByCurrentLocation(latitude, longitude);
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
//await ์ฐ๊ณ ์ ํ๋ ํจ์๋ async ์ฌ์ผ ํ๋ค!
const getWeatherByCurrentLocation = async (lat, lon) => {
let url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
let response = await fetch(url) //๋น๋๊ธฐ(์ง๋
: url์ patchํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ!) : url ๋ก๋ฉํ ๋ค ์๋ต๊ฐ์ ๋ฐ๊ธฐ๋ก ํจ
let data = await response.json(); //์๋ต์์ json ์ถ์ถํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ
setUserWeather(data);
console.log(data);
}
const getWeatherByCity = async () => {
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
//
let response = await fetch(url) //๋น๋๊ธฐ(์ง๋
: url์ patchํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ!) : url ๋ก๋ฉํ ๋ค ์๋ต๊ฐ์ ๋ฐ๊ธฐ๋ก ํจ
let data = await response.json(); //์๋ต์์ json ์ถ์ถํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ
setUserWeather(data);
console.log(data);
}
useEffect(() => {
if (city == "Your Weather") {
getCurrentLocation();
} else {
getWeatherByCity('city', city);
}
}, [city]);
return (
<div>
<div className="sweet-loading">
<button onClick={() => setLoading(!loading)}>Toggle Loader</button>
<input value={color} onChange={(input) => setColor(input.target.value)} placeholder="Color of the loader" />
<ClipLoader
color={color}
loading={loading}
size={150}
aria-label="Loading Spinner"
data-testid="loader"
/>
</div>
<div className='main'>
<WeatherBox weather={userWeather} />
<WeatherButton cities={cities} setCity={setCity} />
</div>
<div>
</div>
</div >
);
}
export default App;
๊ธฐ๋ณธ ๊ฐ์ ์๋์ ๊ฐ์ด ํด์ฃผ๋,
let [loading, setLoading] = useState(false);
๋ฐ์ดํฐ๋ฅผ fetch ํ๋ ๋์ true๋ก ํด์ฃผ๋ ๋ก์ง์ผ๋ก ๋ฐ๊พธ์ด์ค๋ค.
fetch๊ฐ ๋๋๋ฉด ๋ค์ false๋ก ๋๋ ค์ค๋ค.
App.js
import './App.css';
import { useEffect, useState } from 'react';
import WeatherBox from "./component/WaetherBox";
import WeatherButton from "./component/WeatherButton";
import ClipLoader from "react-spinners/ClipLoader";
import 'bootstrap/dist/css/bootstrap.min.css';
//1. ์ฑ์ด ์คํ๋์๋ง์ ํ์ฌ ์์น ๊ธฐ๋ฐ์ ๋ ์จ๊ฐ ๋ณด์ธ๋ค.
//2. ๋ ์จ ์ ๋ณด์๋ ๋์, ์ญ์จ, ํ์จ ๋ ์จ ์ํ
//3. 5๊ฐ์ ๋ฒํผ์ด ์๋ค (1๊ฐ๋ ํ์ฌ ์์น, 4๊ฐ๋ ๋ค๋ฅธ ๋์)
//4. ๋ก๋ฉ ์คํผ๋ ๊ธฐ๋ฅ ์ถ๊ฐ
function App() {
const [userWeather, setUserWeather] = useState(null);
const [city, setCity] = useState("Your Weather");
const cities = ['Your Weather', 'new york', 'toronto', 'paris', 'rondon'];
let [loading, setLoading] = useState(false);
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
getWeatherByCurrentLocation(latitude, longitude);
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
//await ์ฐ๊ณ ์ ํ๋ ํจ์๋ async ์ฌ์ผ ํ๋ค!
const getWeatherByCurrentLocation = async (lat, lon) => {
let url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
setLoading(true);
let response = await fetch(url) //๋น๋๊ธฐ(์ง๋
: url์ patchํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ!) : url ๋ก๋ฉํ ๋ค ์๋ต๊ฐ์ ๋ฐ๊ธฐ๋ก ํจ
let data = await response.json(); //์๋ต์์ json ์ถ์ถํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ
setUserWeather(data);
setLoading(false);
console.log(data);
}
const getWeatherByCity = async () => {
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
setLoading(true);
let response = await fetch(url) //๋น๋๊ธฐ(์ง๋
: url์ patchํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ!) : url ๋ก๋ฉํ ๋ค ์๋ต๊ฐ์ ๋ฐ๊ธฐ๋ก ํจ
let data = await response.json(); //์๋ต์์ json ์ถ์ถํ๋ ๊ฒ์ ๊ธฐ๋ค๋ ค๋ฌ๋ผ
setUserWeather(data);
setLoading(false);
console.log(data);
}
useEffect(() => {
if (city == "Your Weather") {
getCurrentLocation();
} else {
getWeatherByCity('city', city);
}
}, [city]);
return (
<div>
<div className='main'>
<ClipLoader className='react-spinners'
color="#ffffff"
loading={loading}
size={150}
aria-label="Loading Spinner"
data-testid="loader"
/>
<WeatherBox weather={userWeather} />
<WeatherButton cities={cities} setCity={setCity} loading={loading} setLoading={setLoading} />
</div>
<div>
</div>
</div >
);
}
export default App;
๊ทธ๋ฆฌ๊ณ ์ด์ํ ๋ก๋ฉ์คํผ๋์ ์์น๋ฅผ ์ฎ๊ฒจ์ฃผ์๋ค.
App.css
body{
background-image : url(https://wallpaperaccess.com/full/5466320.jpg);
height: 100vh;
width: 100%;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
.main{
display: flex;
flex-direction: column;
margin: auto;
justify-content: center;
justify-content: space-evenly;
height: 100vh;
}
.weather-info-parents{
display: flex;
justify-content: center;
}
.weather-info{
width: 800px;
border: 3px solid #aec6fe;
border-radius: 10px;
color: white;
background-color:rgba(108, 144, 202, 0.4);
padding: 100px;
}
.weather-info-text {
width: 100%;
text-align: center;
padding: 3px;
}
.cityButtonGroup{
display: flex;
justify-content: center;
justify-content: space-evenly;
align-items: center;
position:relative;
width: 100%;
overflow: hidden;
}
.react-spinners{
position:absolute;
width: 100%;
top: 30%;
left: 47%;
}
์ด์ , ์ฌ๊ธฐ์ ๋ก๋ฉ์คํผ๋๊ฐ ๋์๊ฐ ๋ weather info์ data ๋ถ๋ถ์ด ์ถ๋ ฅ๋์ง ์๋๋ก ํ์ฌ ์ต์ข ์ฝ๋๋ฅผ ์์ฑํ๋ค.
App.js
import './App.css';
import { useEffect, useState } from 'react';
import WeatherBox from "./component/WaetherBox";
import WeatherButton from "./component/WeatherButton";
import ClipLoader from "react-spinners/ClipLoader";
import 'bootstrap/dist/css/bootstrap.min.css';
function App() {
const [userWeather, setUserWeather] = useState(null);
const [city, setCity] = useState("Your Weather");
const cities = ['Your Weather', 'new york', 'toronto', 'paris', 'rondon'];
let [loading, setLoading] = useState(false);
const getCurrentLocation = () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition((position) => {
const latitude = position.coords.latitude;
const longitude = position.coords.longitude;
getWeatherByCurrentLocation(latitude, longitude);
});
} else {
alert("Geolocation is not supported by this browser.");
}
}
const getWeatherByCurrentLocation = async (lat, lon) => {
let url = `https://api.openweathermap.org/data/2.5/weather?lat=${lat}&lon=${lon}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
setLoading(true);
let response = await fetch(url)
let data = await response.json();
setUserWeather(data);
setLoading(false);
console.log(data);
}
const getWeatherByCity = async () => {
let url = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=b13282392fd34dd9436686c7c7ecda83&units=metric`;
setLoading(true);
let response = await fetch(url)
let data = await response.json();
setUserWeather(data);
setLoading(false);
console.log(data);
}
useEffect(() => {
if (city == "Your Weather") {
getCurrentLocation();
} else {
getWeatherByCity('city', city);
}
}, [city]);
return (
<div>
{loading ? <div className='main'>
<ClipLoader className='react-spinners'
color="#ffffff"
loading={loading}
size={150}
aria-label="Loading Spinner"
data-testid="loader"
/>
<WeatherBox weather={null} />
<WeatherButton cities={cities} setCity={setCity} loading={loading} setLoading={setLoading} />
</div> :
<div className='main'>
<WeatherBox weather={userWeather} />
<WeatherButton cities={cities} setCity={setCity} loading={loading} setLoading={setLoading} />
</div>}
<div>
</div>
</div >
);
}
export default App;
App.css
body{
background-image : url(https://wallpaperaccess.com/full/5466320.jpg);
height: 100vh;
width: 100%;
background-repeat: no-repeat;
background-size: cover;
background-position: center;
}
.main{
display: flex;
flex-direction: column;
margin: auto;
justify-content: center;
justify-content: space-evenly;
height: 100vh;
}
.weather-info-parents{
display: flex;
justify-content: center;
}
.weather-info{
width: 800px;
border: 3px solid #aec6fe;
border-radius: 10px;
color: white;
background-color:rgba(108, 144, 202, 0.4);
padding: 100px;
}
.weather-info-text {
width: 100%;
text-align: center;
padding: 3px;
}
.cityButtonGroup{
display: flex;
justify-content: center;
justify-content: space-evenly;
align-items: center;
position:relative;
width: 100%;
overflow: hidden;
}
.react-spinners{
position:absolute;
width: 100%;
top: 30%;
left: 47%;
}
WeatherBox.js
import React from 'react'
const WaetherBox = ({ weather }) => {
return (
<div className='weather-info-parents'>
<div className='weather-info'>
<h3 className='weather-info-text'>๋์ {weather?.name}</h3>
<h2 className='weather-info-text'>์ง๊ธ ์จ๋ {weather?.main?.temp} / ์ต๋ {weather?.main?.humidity}</h2>
<h2 className='weather-info-text'>๋์ ๋ ์จ๋? {weather?.weather[0]?.description}</h2>
</div>
</div>
)
}
export default WaetherBox
WeatherButton.js
import React from 'react'
import { Button } from 'react-bootstrap';
const WeatherButton = ({ cities, setCity }) => {
return (
<div className='cityButtonGroup'>
{cities.map((item, index) => (<Button variant="primary" key={index}
onClick={() => {
setCity(item)
}}
>{item}</Button>))}
</div>
)
}
export default WeatherButton