[筆記]react-nasa每日照片範例

*為了想清掉多餘不會再用的練習檔,記錄下每個範例值得學習的地方

api-key的設定

  • 在資料夾第一層設定.env

    REACT_APP_NASA_KEY ="****key****"

  • *.gitignore要設定.env

  • 需要發api的component取得key

    const apiKey = process.env.REACT_APP_NASA_KEY;

此範例架構

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是react hook的一部份
    1. `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>
    2. Lazy initial state
    3. 當你即將 update 的 state 與前一個 state 相同,這次的 update 並不會產生 re-render

留言

這個網誌中的熱門文章

言之有物

天天都要跟自己對話幾百次