[筆記]react-nasa每日照片範例
*為了想清掉多餘不會再用的練習檔,記錄下每個範例值得學習的地方
api-key的設定
在資料夾第一層設定
.env檔REACT_APP_NASA_KEY ="****key****"
需要發api的component取得key
const apiKey = process.env.REACT_APP_NASA_KEY;
*.gitignore要設定.env
此範例架構
import React from 'react';
import {BrowserRouter,Route} from 'react-router-dom';
import Home from './components/Home';
import NasaPhoto from './components/NasaPhoto';
import './App.css';
export default function App(){
return (
<BrowserRouter>
<div className="app">
<Route component={Home} path="/" exact={true} />
<Route component={NasaPhoto} path="/nasaphoto" />
</div>
</BrowserRouter>
)
}
- 小專案可以使用BrowserRouter,Route來指定path(spa內)
Home.js
import React from "react";
import { Link } from "react-router-dom";
export default function Home(){
return(
<div className="home">
<Link className="home-link" to="/nasaphoto">See into the stars!</Link>
</div>
)
}
NasaPhoto.js
import React, {useState, useEffect} from 'react';
import NavBar from "./NavBar";
const apiKey = process.env.REACT_APP_NASA_KEY;
export default function NasaPhoto() {
const [photoData, setPhotoData] = useState(()=>{
const initialState = null;
return initialState;
})
useEffect(() => {
fetchPhoto();
async function fetchPhoto(){
const res = await fetch(`https://api.nasa.gov/planetary/apod?api_key=${apiKey}`);
const data = await res.json();
setPhotoData(data)
}
}, []);
if(!photoData) return <div/>
return(
<>
<NavBar />
<div className="nasa-photo">
{photoData.media_type === "image" ? (
<img
src={photoData.url}
alt={photoData.title}
className="photo"
/>
) : (
<iframe
title="space-video"
src={photoData.url}
frameBorder="0"
gesture="media"
allow="encrypted-media"
allowFullScreen
className="photo"
/>
)}
<div>
<h1>{photoData.title}</h1>
<p className="date">{photoData.date}</p>
<p className="explanation">{photoData.explanation}</p>
</div>
</div>
</>
)
}
NavBar.js
import React from 'react';
import { Link } from 'react-router-dom';
export default function NavBar(){
return(
<div className="navbar">
<ul>
<Link className="link" to="/" exact={"true"}>Take Me Home</Link>
</ul>
</div>
)
}
簡單測試範例: App.test.js
import React from 'react';
import { render } from '@testing-library/react';
import App from './App';
test('renders See into the stars link', () => {
const { getByText } = render(<App />);
const linkElement = getByText(/See into the stars/i);
expect(linkElement).toBeInTheDocument();
});
截圖:
問題1:
- 為何選擇使用useState, useEffect來發api好處是啥??相關文章:關於-usestate-你需要知道的事
看完上面文章來整理和hook相關的資訊
- useState是react hook的一部份
- `useState` 中的 state update function 是一個「非同步」function
const [photoData,setPhotoData] =useState(null);setPhotoData就是 state update function
-
*要注意會使用過去的state來做update時,會因為非同步而產生誤差
以下這是不安全的做法
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1)}>加一</button>以下是安全的做法
<button onclick="{()"> setCount(prevCount => prevCount + 1)}>加一</button>function 的寫法讓 `setCount` 變成「同步」的,保證了執行順序,當你執行 `setCount` ,一定會等 update 完 state 後再做下一件事。
-
*要小心:在 set state 後執行 function
可能會有問題
const [count, setCount] = useState(0);
<button onclick="{()"> {setCount(count + 1)console.log(count)}}>加一</button>使用useEffect較無問題
const [count, setCount] = useState(0); useEffect(() => { console.log(count)}, [count]); <button onclick="{()">{setCount(count + 1)}}>加一</button>
-
- Lazy initial state
- 當你即將 update 的 state 與前一個 state 相同,這次的 update 並不會產生 re-render
留言
張貼留言