iT邦幫忙

0

(自己回答自己)Re: 關於新手入門React+TypeScript遇到的困擾⋯

  • 分享至 

  • xImage
  •  

原篇發問網址在這:https://ithelp.ithome.com.tw/questions/10211232

前言
這篇是我自己發問的,最後搞很久,才終於寫出一個可以發送請求,並拿到數據也成功展示資料給用戶。
因為用這個IT邦才不久,不確定能不能在回答處直接寫代碼,所以乾脆再寫一篇自己解決的後續,分享給如果有跟我一樣卡TS卡很久的夥伴QQ,順便也記錄一下心得留給自己以後能再回顧。

ps. 有些地方我自己覺得還不夠好,像是偷用any之類,感覺有點偷吃步XD,反正只能再繼續多練了QQ"

正題

先上代碼,如果不知道前因後果的人,可以先去上面原發問連結稍微看一下,雖然文很長QQ,謝謝。
(這篇就不附上兩個json檔的內容,怕同頁上下觀看不方便,可以從原文連結去看)

FetchData.tsx

import axios, { AxiosError } from 'axios'
import { MyResponse } from '../components/ShowData'

const FetchData = (url: string) => {

  const getData = async () => {
    try {
      const res = await axios(url)
      return res.data
    } catch (err) {
      return err
    }
  }

  const checkStatus = (promise: Promise<any>) => {
    let status = 'pending'
    let result: unknown = ''
    let suspender = promise.then((r) => {
      status = 'success'
      result = r
    }, (e: AxiosError) => {
      status = 'error'
      result = e
    })

    return {
      read: () => {
        if (status === 'pending') {
          throw suspender
        } else if (status === 'error') {
          return result as MyResponse
        }
        return result as MyResponse
      }
    }
  }

  return {
    data: checkStatus(getData())
  }
}

export default FetchData

ShowData.tsx

type Props = {
  resource: {
    data: {
      read: () => MyResponse
    }
  }
}

interface Title<S = string> {
  name: S
  svgClass: S
  path: {[key: string]: S}
}

interface Work<S = string> {
  company: S
  position: S
  year: S
  location: S
  industry: S
  descriptions: {[key: string]: S}
}

interface Education<S = string> {
  school_en: S
  school_cn: S
  year: S
  status: S
}

export interface MyResponse {
  title: Title
  OOO?: Work
  XXX?: Work
  OXOX?: Work
  college?: Education
  high_school?: Education
  name?: string
  message?: string
}

const ShowData = ({resource}: Props) => {

  const _data = resource.data.read()

  return (
    <div>
      {_data.name === 'AxiosError' ? _data.message : _data.title.name}
    </div>
  )
}

export default ShowData

雖然我知道ShowData組件中的MyResponse型別定義這樣寫有很高的機率能夠不報錯,因為等於直接把所有可能的資料(返回的對象)的屬性(properties)全部寫上,那當然就能沒有錯誤,因為有點把東西寫死的概念(但如果今天資料量很龐大的話...QQ)。

原本是有打算這樣寫的:

export interface MyResponse {
  [key: string]: Title | Work | Education
}

但不知道為什麼,這樣寫都一直會報錯說,型別不對,不能某某型別賦給某某型別,所以只好放棄

如果可以的話,我是想寫成動態的(像上面那樣簡潔,一行可判斷多種),但暫時寫的項目沒有那麼多的資料需要拿,因此(暫時的解法)就把所有都寫上去,如果有什麼更好的方法的話,還請各位在下面留言分享告訴我,謝謝。

App.tsx

import {Suspense} from 'react'
import FetchData from './helpers/FetchData';
import ShowData from './components/ShowData';

const resource = FetchData("/data/works.json");

function App() {

  return (
    <div>
      <Suspense fallback={<h1>Loading...</h1>}>
        <ShowData resource={resource} />
      </Suspense>
    </div>
  );
}

export default App;

以上就是整個代碼了,最後也是成功能展示資料的,包括展示錯誤訊息。

如此一來,我就可以不用自己每個發請求的組件,一直重複寫三個state:isLoading, ErrorMsg, data了。
直接就能依靠React自帶的Suspense組件,幫我判斷是否還在加載中、發生錯誤,或是資料已回來可以展示給用戶,超方便!


圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言