iT邦幫忙

2021 iThome 鐵人賽

DAY 8
0
Modern Web

All In One NFT Website Development系列 第 8

Day 8【錢包登入區 - Loading Message】阿嬤為什麼妳有感覺?

【前言】
一樣先來回顧一下 Day2 Project 分析的使用者流程,今天來做第二步的**「驗證帳號讀取時的 Loading 特效」**。我發現寫 React 的心路歷程跟這個廣告很像,一下子在想為什麼沒感覺,一下子又在想為什麼你有感覺。很多東西到底怎麼出現的自己也不是很了解哈哈哈哈哈哈哈哈哈哈。

【(使用者看見的)前端與(後方運作的)後端】

  1. 使用者會看見登入錢包按鈕(按鈕應該要有一些特效)
    • 按下按鈕後要連到 MetaMask 系統
  2. 使用者點擊按鈕後出現 Loading 特效,同時跳出 Metamask 登入及連動同意
    • 同意後,要從 MetaMask 得到當前登入者的以太坊地址
  3. 使用者同意後出現登入介面,讓其輸入欲登入的角色編號
    • 得到欲登入的角色編號後,去後方資料庫查詢此地址是否真的擁有此 NFT
      // 資料庫建構的部分由其他夥伴負責,這邊我負責檢查 Tokens 的持有地址
  4. 成功登入後的畫面
    // 網頁互動的部分由其他夥伴負責,這邊我負責顯示登入成功 or 失敗

【Loading Message】
利用到 Day 6 學到的 setIsPending() 來輸出 Loading Message。目前我的設想是:在使用者點下登入按鈕之後,跳出 MetaMask 的 API,到系統後端確認登入的這段時間,頁面都要呈現 Loading Message 或相關特效。

首先在 index.jsx import useEffect()useState()

import { useEffect, useState } from "react";

再來在 function return 之前加上 useState() 的敘述。

export function AccountBox(props) {
  ...
  const [isPending, setIsPending] = useState(true);
	...
  return (
    <AccountContext.Provider value={contextValue}>
      ...
		</AccountContext.Provider>
  );
}

useState() 的宣告以及return 之間加入 useEffect() 來隨時隨地偵測是否需要產出 Loading Message。附帶一提,這邊當然是為了讓 Loading 的效果出現才會特別用 setTimeout() 哈哈哈哈哈哈哈哈。因為我還沒有架設 json 的伺服器來供利用所以可以先忽略 fetch 的部分。

useEffect(() => {
  setTimeout(() => {
    fetch('...')
    .then(res => {
      return res.json();
    })
    .then(data => {
      setIsPending(false);
    })
  }, 1000);
}, [])

目前的結果呈現是這樣,但跟我想像中的不一樣,應該要只出現 Loading Message,Loading 結束之後才出現登入介面才對! 後來才知道是我應該增加一個 bool 來選擇在 Loading 時先不要出現 <BoxContainer> ... </BoxContainer> 的資訊內容,等 Loading 結束後 isPending() == false 才會輸出登入介面。

export function AccountBox(props) {
  ...
  const [isPending, setIsPending] = useState(true);
	...
	useEffect(() => {
    setTimeout(() => {
      setIsPending(false);
    }, 1000);
  }, [])
	...
  return (
    <AccountContext.Provider value={contextValue}>
      { active === "signin" && (
        <LoginWrapper>
          { isPending && <div>Loading...</div> }
          <BoxContainer>
						...
					</BoxContainer>
        </LoginWrapper>
      )}
    </AccountContext.Provider>
  );
}

原本以為這個過程很簡單,沒想到在 useEffect() 上的 BUG 一堆,Loading Message 在 return 裡面的位置也需要思考一下。經過精簡再精簡的排除之後完整的程式碼大概長這樣!之後會把 json 的利用加回來,希望大家好好期待,這裡先著重在 Loading Message 的呈現。

export function AccountBox(props) {
  ...
  const [isPending, setIsPending] = useState(true);
	...
	useEffect(() => {
    setTimeout(() => {
      setIsPending(false);
    }, 1000);
  }, [])
	...
  return (
    <AccountContext.Provider value={contextValue}>
      <LoginWrapper>
        { isPending && <div>Loading...</div> }
				{ !isPending && 
					<BoxContainer>
						...
					</BoxContainer>
				}
      </LoginWrapper>
    </AccountContext.Provider>
  );
}

【Loading Effect】
現在要開始對 Loading Message 加入特效,主要就是對 <div>Loading...</div> 這塊進行變化!如果只有使用 div 輸出文字的話是長這樣:(非常陽春)

經過在網路上多方尋找之後,我發現了一個非常棒的東西很符合需求,使用起來也沒有那麼複雜!首先來到以下這個網站找一個自己喜歡的 Loading 圖樣,然後調整自己喜歡的顏色、速度、尺寸。

React Spinners

然後在Command Line 執行以下程序:

npm install --save react-spinners

並且在 index.jsx 之中引入套件。其中 "~" 的部分為自己想要的 Loading 圖樣的名稱,我選擇的是 RingLoader,範例如下:

import ~ from "react-spinners/~";

e.g.
import RingLoader from "react-spinners/RingLoader";

這邊我使用的 Loading 特效及程式碼是這樣,因為發現可以覆寫 CSS 所以我對他做一點改變。

{ isPending && 
	<RingLoader 
		size={170} 
		color={"#36D7B7"} 
		loading={isPending} 
		speedMultiplier={1.05} 
		css={override} />
}

記得在覆寫 CSS 之前要先 import emotion

import { css } from "@emotion/react";

const override = css`
  display: block;
  margin: 112% auto;
  overflow:hidden;
`;

呈現的結果非常不錯!

原本我直接把程式碼丟進去 return 的時候想說今天的內容也未免太簡單了,結果 compiler error 了好久,他一直告訴我 "loading" 沒有宣告過,後來才發現原來我是使用 isPending 來當作是否在 Loading 的 bool。

【小結】
React 讓我有一種又驚又喜又怕,既期待又怕受傷害的感覺,每次看到很棒的特效或者前端的時候都會想實作看看,但每次元件的複雜程度還有未知的 BUG 都會一次次的打擊信心。不過我會繼續加油的,畢竟跟一開始完全對前端毫無涉獵的我相比,現在已經進步很多了吧!

【參考資料】
react-spinners
CSS overflow 屬性用法


上一篇
Day 7【錢包登入區 - Login Button】Kitten or Ice Cream?
下一篇
Day 9【錢包登入區 - Login Interface】你也想起舞嗎?
系列文
All In One NFT Website Development30

尚未有邦友留言

立即登入留言