iT邦幫忙

2021 iThome 鐵人賽

DAY 17
0
自我挑戰組

Re: 從 Next.js 開始的 React 生活系列 第 17

[Day17] 學 Reactstrap 就離 React 不遠了 ~ 用 Spinners 搭配複習 Flex, useState, useEffect 三個願望一次滿足!

前言

雖然昨天的文章有提到我想在 Codecademy 開始打 React 的基礎,
不過看前幾天我的文章順序是 認識 useState、熟悉 useState、認識 useEffect
所以今天應該要排一個熟悉 useEffect XD
而剛好看到一個我之前沒注意到的 component,
所以就順便來個綜合練習吧~~~

本日正文

用 Flex 排出奧運五環圖案

今天要為大家介紹的 component 是 Spinners
看到這樣的色系不覺得會讓人聯想到奧運的五環圖案嗎XD
所以我今天想要用 Spinners 來弄奧運的圖示XD
https://ithelp.ithome.com.tw/upload/images/20210919/20129873RNvkWO7YZF.png

Spinners 去查中文意思會發現有旋轉球, 穿針引線, 紡線者的意思,
總之在網頁的世界看到 Spinners 就表示這種會旋轉的 loading 圖示。

然後一開始我在 CodeSandbox 貼以下範例程式時,
不知道為什麼中間會多 Loading 的字樣= ="

<div>
    <Spinner color="secondary" />
    <Spinner color="success" />
    <Spinner color="danger" />
    <Spinner color="warning" />
    <Spinner color="info" />
    <Spinner color="light" />
    <Spinner color="dark" />
</div>

https://ithelp.ithome.com.tw/upload/images/20210919/20129873XGfFxWVWFh.png

所以我只好把範例改寫成這樣:

<div>
  <Spinner color="info">{' '}</Spinner>
  <Spinner color="dark">{' '}</Spinner>
  <Spinner color="danger">{' '}</Spinner>
  <Spinner color="warning">{' '}</Spinner>
  <Spinner color="success">{' '}</Spinner>
</div>

https://ithelp.ithome.com.tw/upload/images/20210919/20129873HJ2a701INS.png

參考奧運五環圖案,

所以挑了 info, dark, danger, warning, success 這五個顏色,
你看這樣是不是就很有奧運五環圖案的 fu 了XD

再來當然要善用 Flex 把這五個環排成跟奧運五環一樣的位置,
首先把五個環拆成兩個 <div>,
然後我又在兩個 <div> 外面包了一個 <div>
並限制寬度(因為不要讓它們以瀏覽器整個寬度去排版),
(PS. 這邊我有另外寫 CSS 處理:

.container {
  width: 12rem;
}

所以在 App.js 記得 import CSS:

import "./styles.css";

)
再來就在 padding, margin 上做一點裝飾,
完成品如下:

<div className="container px-4 mt-2">
    <div className="px-2 d-flex justify-content-between">
      <Spinner color="info"> </Spinner>
      <Spinner color="dark"> </Spinner>
      <Spinner color="danger"> </Spinner>
    </div>
    <div className="px-4 d-flex justify-content-around">
      <Spinner color="warning"> </Spinner>
      <Spinner color="success"> </Spinner>
    </div>
</div>

https://ithelp.ithome.com.tw/upload/images/20210919/20129873WVKCe7efj0.png

用 useEffect & setTimeout 弄出時間差顯示

到這邊排版的部份就告一段落,
再來就是為了也要練習 useState, useEffect,
我想了一下,決定弄成2020東京奧運佳績榜,
一開始畫面顯示「載入中......」,
倒數 3 秒後才會顯示下方的奧運佳績榜,
這樣要怎麼做呢?

首先先把最後想呈現畫面刻出來,
先不要想邏輯,
像這樣:

import "../node_modules/bootstrap/dist/css/bootstrap.min.css";
import React, { useState, useEffect } from "react";
import { Spinner } from "reactstrap";
import "./styles.css";

export default function App() {
  return (
    <>
      <div className="container px-4 mt-2">
        <div className="px-2 d-flex justify-content-between">
          <Spinner color="info"> </Spinner>
          <Spinner color="dark"> </Spinner>
          <Spinner color="danger"> </Spinner>
        </div>
        <div className="px-4 d-flex justify-content-around">
          <Spinner color="warning"> </Spinner>
          <Spinner color="success"> </Spinner>
        </div>
      </div>
      <div className="m-4">
        <h3 className="text-center">2020東京奧運佳績榜</h3>
        <p className="text-center">載入中......</p>
          <div>
            <h4>?金牌</h4>
            <ul>
              <li>舉重女子59公斤級:郭婞淳</li>
              <li>羽球男子雙打:李洋、王齊麟</li>
            </ul>
            <h4>?銀牌</h4>
            <ul>
              <li>羽球女子單打:戴資穎</li>
              <li>競技體操男子鞍馬:李智凱</li>
              <li>柔道男子60公斤(含)以下級:楊勇緯</li>
              <li>射箭男子團體賽:湯智鈞、魏均珩、鄧宇成</li>
            </ul>
            <h4>?銅牌</h4>
            <ul>
              <li>跆拳道女子49-57公斤級:羅嘉翎</li>
              <li>舉重女子64公斤級:陳玟卉</li>
              <li>拳擊女子51公斤蠅量級:黃筱雯</li>
              <li>空手道:文姿云</li>
              <li>高爾夫男子個人比桿賽:潘政琮</li>
              <li>桌球混合雙打:林昀儒、鄭怡靜</li>
            </ul>
          </div>
      </div>
    </>
  );
}

https://ithelp.ithome.com.tw/upload/images/20210919/20129873sIZGNCSyjj.png

再來思考一下這樣該怎麼做:

倒數 3 秒後才會顯示下方的奧運佳績榜

相信大家對 setTimeout 並不陌生,
setTimeout 就是可以設定幾秒後執行 function,
(setInterval 則是設定每幾秒就執行一次 function)
因此像這樣的 setTimeout 這樣的 function,
也是 useEffect 的服務範圍,
就是當頁面(組件)渲染後且會有變化就要執行,
所以我們先在 useEffect 寫上 setTimeout:

useEffect(() => {
    setTimeout(() => {

    }, 3000);
});

(3000 就是 3 秒後要執行裡面 function 的意思)

想一下我們 3 秒後要執行的動作:

  1. 「載入中......」文字變成「2金-4銀-6銅」
  2. 奧運佳績榜從不顯示到顯示出來

所以前面先這樣宣告:

const shortText = "載入中......";
const longText = "2金-4銀-6銅";
const [text, setText] = useState(shortText);
const [isShow, setIsShow] = useState(false);

前面三行是狀態文字的部份,
第四行是為了要控制奧運佳績榜的顯示與否。
(預設值當然是 false)

這樣答案很明顯了,
我們要在 setTimeout 裡面寫 setText 及 setIsShow,
像這樣:

useEffect(() => {
    setTimeout(() => {
      setText(longText);
      setIsShow(true);
    }, 3000);
});

但你發現奧運佳績榜從一開始就會出現,
要怎麼讓它一開始不出現,3 秒後才出現?
這邊要介紹一個 React 的語法,
直接寫在網頁元素中,
架構長這樣:

{ 變數(條件) ? (
    <div>
    ...
    ...
    </div>
): null }

這個意思是,會去判斷 變數(條件)
true 的話會顯示 ? (...) 的內容,
false 的話則會顯示 : 後面的內容。
(PS. : 後面設定 null 就是空值,也就是當 false 時不要顯示任何內容)

所以我們在奧運佳績榜那段要這樣改寫:

{isShow ? (
  <div>
    <h4>?金牌</h4>
    <ul>
      <li>舉重女子59公斤級:郭婞淳</li>
      <li>羽球男子雙打:李洋、王齊麟</li>
    </ul>
    ...
    ...(略)
  </div>
) : null}

然後在上面的 <p className="text-center">載入中......</p>
也要記得改寫成這樣才會在倒數 3 秒前後產生不同變化:
<p className="text-center">{text}</p>

讓我們來看看成果:

是不是很有趣!!!!!!

useState, useEffect 就可以產生這樣的變化!
尤其我覺得這個寫法實在是太讓人驚豔了XD

{ 變數(條件) ? (
    <div>
    ...
    ...
    </div>
): null }

在之前寫純 HTML/CSS, JavaScript 的時候真的很難想像,
在純 JavaScript 的世界裡,
要改變文字內容我們通常會這樣寫對吧?

const element = document.getElementById('title');
if (...){
	element.textContent = '這是舊標題';
} else {
	element.textContent = '這是新標題';
}

或要控制它的顯示與否,
我們會這樣寫:

const element = document.getElementById('title');
if (...){
	element.style.display = "block";
} else {
	element.style.display = "none";
}

要先用 getElementById 拿到元件,
然後再寫 if else 判斷式,
再用 textContent 改變它的文字內容,
或寫 style.display 控制元件的顯示與否,
每次光想到要寫 getElementById 就覺得累orz
可是 React 透過這樣的方式讓人可以很直覺方便的控制網頁上的元件,
所以真的會越寫越愛 React XD

不過我覺得這一段還是必經過程啦,
這樣會更了解 DOM 的運作方式之類的,
蹲馬步還是必要的XD
這樣之後學輕功才會比較快上手XD
而且也會比較紮實XD

一樣附上今日練習:Day17 - Reactstrap (Spinners)

大家也快來玩玩看吧~~~~

後記

今日練習一不小心玩太多XD
其實一開始只是看到 Spinners 的範例覺得長得很像奧運五環圖案,
然後就變這樣了XD"
應該明天開始就會 Codecademy 了吧(希望
那我們明天見囉!

追加

剛才一直看到 3 秒後 Spinners 卻還在轉覺得有點煩XD
所以我小小改了 Spinners 的這段:

<div className="container px-4 mt-2">
    {!isShow ? (
      <>
        <div className="px-2 d-flex justify-content-between">
          <Spinner color="info"> </Spinner>
          <Spinner color="dark"> </Spinner>
          <Spinner color="danger"> </Spinner>
        </div>
        <div className="px-4 d-flex justify-content-around">
          <Spinner color="warning"> </Spinner>
          <Spinner color="success"> </Spinner>
        </div>
      </>
    ) : (
      <img
        alt="Olympic"
        src="https://upload.wikimedia.org/wikipedia/commons/thumb/5/5c/Olympic_rings_without_rims.svg/380px-Olympic_rings_without_rims.svg.png"
        width="80%"
      />
    )}
  </div>

這意思是當 !isShow 為 true 時要顯示 Spinners,
反之只要顯示靜態圖片就好,
所以當 isShow 是 false 時會顯示 Spinners 動畫,
isShow 是 true 時會顯示奧運五環的靜態圖片。
(這樣就剛好完整介紹了這個架構XD)

{ 變數(條件) ? (
    <div>
    ...
    ...
    </div>
): (
    ...
    ...
)}

改完後成果:


上一篇
[Day16] 學 Reactstrap 就離 React 不遠了 ~ 用 Tooltips 認識 useEffect
下一篇
[Day18] 跟我一起從頭學 React 吧!Let's start learning React from Codecademy! ~ Intro to JSX 篇
系列文
Re: 從 Next.js 開始的 React 生活30

尚未有邦友留言

立即登入留言