iT邦幫忙

2023 iThome 鐵人賽

DAY 21
0
自我挑戰組

用ChatGPT詠唱來完成工作與點亮前後端技能樹系列 第 21

【Day21】ChatGPT請教教我:React入門(七)- React & TypeScript !

  • 分享至 

  • xImage
  •  

目前這個系列已挑選ChatGPT、前端&React相關章節出版成書!
感謝大家的閱讀與支持!
《用 ChatGPT 詠唱來點亮 React & 前端技能樹》
歷經重新整理、校正、編排、與修改後,讓章節內容之間的銜接更平順,除了補充上更多的解說之外,甚至有部分章節為重新撰寫的內容,讓理解變得更輕鬆!
目前已在天瓏書局博客來金石堂等通路都買得到了! 也有電子書的選擇!
歡迎各位點擊連結選購,謝謝大家~
https://ithelp.ithome.com.tw/upload/images/20240419/20135750lQM12by6v1.jpg


這個章節終於要幫我們的React專案加上TypeScript了
有關基礎的TypeScript內容
可以先看:【Day10】ChatGPT請教教我:TypeScript!Enum!泛型 !

一開始進行React教學的時候
我請ChatGPT建置了包含TypeScript版本的CRA專案:

npx create-react-app my-react-app --template typescript

(如果一開始沒有加上 --template typescript 就是沒有typeScript建置的)

後來發現,剛開始學的時候,有加上TypeScript會有那麼億…點點太複雜啊
所以這中間的教學中,沒有用到TypeScript

為了拯救我們的TypeScript戒斷症,這個章節會總覽Day15~ Day20的語法與內容
著重在一些React 語法要如何搭上TypeScript來開發

Go Go!

React CRA 加上TypeScript建置

先說一下,目前React相關建置框架,基本上都有支援TypeScript
如果一開始在用CRA沒有建立TypeScript相關設定的話

要怎麼替專案加上設定呢?
先初步問看看要如何開始
https://ithelp.ithome.com.tw/upload/images/20231003/2013575024Hbrlb71u.png

嗨!對於一名初學者來說,要在 React 中使用 TypeScript 是一個很好的選擇,因為它可以幫助你更容易地處理類型相關的錯誤。

以下是一個簡單的步驟來在 React 專案中使用 TypeScript:

步驟 1: 建立一個新的 React 專案

如果你還沒有一個 React 專案,你可以使用 Create React App 來建立一個新的專案,並選擇 TypeScript 作為模板。

npx create-react-app my-app --template typescript
cd my-app

步驟 2: 安裝 TypeScript 相關的套件

Create React App 會自動幫你安裝 TypeScript 相關的套件,但如果你是在一個已經存在的專案中添加 TypeScript,你可以執行以下指令:

npm install --save typescript @types/node @types/react @types/react-dom @types/jest

步驟 3: 創建你的第一個 TypeScript 檔案

src 目錄中創建一個新的 TypeScript 檔案,例如 App.tsx,並開始編寫你的 React 組件。

// src/App.tsx

import React from 'react';

const App: React.FC = () => {
  return (
    <div>
      <h1>Hello, TypeScript with React!</h1>
    </div>
  );
};

export default App;

步驟 4: 開始編寫 React 組件

現在你可以開始編寫你的 React 組件,並使用 TypeScript 來聲明 props 的型別,以及為函數組件添加適當的型別。

// src/MyComponent.tsx

import React from 'react';

interface MyComponentProps {
  name: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ name }) => {
  return <div>Hello, {name}!</div>;
};

export default MyComponent;

步驟 5: 使用你的 React 組件

在其他地方使用你剛剛定義的組件:

// src/App.tsx

import React from 'react';
import MyComponent from './MyComponent';

const App: React.FC = () => {
  return (
    <div>
      <h1>Hello, TypeScript with React!</h1>
      <MyComponent name="John" />
    </div>
  );
};

export default App;

步驟 6: 開始開發

現在你已經準備好使用 TypeScript 開發 React 專案了!記得在開發過程中根據需要為組件和函數添加正確的型別。

希望這份步驟對你有所幫助!如果你有任何其他問題,隨時告訴我。

Props & TypeScript

上面提及了如何追加安裝TypeScript,也初步展示了要如何對Props加上type
我個人習慣的component會是直接用function定義的方式,副檔名使用.tsx/.jsx
類似…

function MyComponent(props) {
  return <div>Hello, {props.name}!</div>;
}

來問看看ChatGPT如果是這個寫法的話,要怎麼加上TypeScript
https://ithelp.ithome.com.tw/upload/images/20231003/20135750on20RrfP5Z.png

當然,我們可以使用函數組件的方式來添加 TypeScript 型別標註到 props。以下是一個使用 TypeScript 的函數組件範例,其中針對 props 加上了型別標註:

import React from 'react';

// 定義 props 的型別
interface MyComponentProps {
  name: string;
}

// 使用函數組件
function MyComponent(props: MyComponentProps) {
  // 從 props 中解構出 name
  const { name } = props;

  return <div>Hello, {name}!</div>;
}

export default MyComponent;

在這個範例中,我們首先使用 interface 定義了 MyComponentProps,並為 name 屬性指定了 string 型別。接著,我們使用函數組件 MyComponent,並將 MyComponentProps 作為 props 的型別。最後,在組件內部,我們可以從 props 中解構出 name

這樣,當你在其他地方使用 MyComponent 時,TypeScript 將會檢查傳遞給它的 props 是否符合所定義的型別,提高了代碼的可靠性。希望這個範例對你有所幫助!如果你有任何進一步的問題,請隨時提出。

OK,樸實無華,就是直接props: MyComponentProps

加上Props的型別指定之後,在使用這個Component的時候
若沒有帶入相關的props,就會跳出警告
https://ithelp.ithome.com.tw/upload/images/20231003/20135750LlfTPdYhBC.png

useState & TypeScript

https://ithelp.ithome.com.tw/upload/images/20231003/20135750MI7jNwGR4u.png

當你在 React 中使用 TypeScript 時,可以使用 useState 來管理組件的狀態。要為其添加型別定義,可以這樣做:

首先,你需要匯入 useStateReact

import React, { useState } from 'react';

接著,你可以使用泛型來指定狀態的型別,例如:

const [count, setCount] = useState<number>(0);

在這個例子中,我們假設 count 是一個數字,因此我們使用 useState<number>(0) 來指定 count 的型別為數字,並將初始值設為 0。

以下是一個完整的範例:

import React, { useState } from 'react';

const Counter: React.FC = () => {
  // 定義狀態 count,並指定型別為數字
  const [count, setCount] = useState<number>(0);

  const increment = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={increment}>Increment</button>
    </div>
  );
};

export default Counter;

這個範例中,我們創建了一個簡單的計數器組件。我們使用 useState<number>(0) 來定義狀態 count,並初始化為 0。然後,我們提供了一個按鈕,當按下時會調用 increment 函數,將計數器的值增加 1。

這樣,你就可以在 React 中使用 useState 並為其添加型別定義了。如果你有其他問題或需要進一步說明,請隨時告訴我!

舒服!我們的State可以加上Type設定了
可以確保我們在進行更新State的時候,可以維持一樣的Type,避免造成變數的型別混亂

InlineStyle CSS & TypeScript

突然發現我們還沒有探討在React Component中加上style的方式
https://ithelp.ithome.com.tw/upload/images/20231003/20135750Rxrf3rYMj2.png

在 React 中,你可以使用兩種主要的方式來添加樣式:

  1. 行內樣式 (Inline Styles): 將樣式直接寫在 JSX 元素的 style 屬性中。
  2. 使用 CSS 檔案: 將樣式寫在獨立的 CSS 檔案中,然後在組件中引入。

以下是這兩種方式的範例:

1. 行內樣式 (Inline Styles)

import React from 'react';

const MyComponent = () => {
  const divStyle = {
    color: 'blue',
    fontSize: '20px'
  };

  return (
    <div style={divStyle}>
      This is a styled div.
    </div>
  );
};

export default MyComponent;

在這個範例中,我們在 div 元素中使用了 style 屬性,並傳遞了一個物件,該物件包含了要應用的樣式。注意,這裡的樣式屬性名稱是使用駝峰式命名法 (camelCase),例如 fontSize

2. 使用 CSS 檔案

首先,在你的專案中創建一個 CSS 檔案,例如 styles.css,並在其中定義你的樣式:

.my-component {
  color: blue;
  font-size: 20px;
}

然後,在你的 React 組件中引入這個 CSS 檔案:

import React from 'react';
import './styles.css';

const MyComponent = () => {
  return (
    <div className="my-component">
      This is a styled div.
    </div>
  );
};

export default MyComponent;

在這個範例中,我們使用 className 屬性來指定元素應用的 CSS 類別,這個類別對應到我們在 styles.css 中定義的 .my-component

你可以根據情況選擇適合你的方式來添加樣式。如果你需要動態地改變樣式,行內樣式可能會更為適用。如果你有任何進一步的問題,請隨時告訴我!

https://ithelp.ithome.com.tw/upload/images/20231003/20135750TzGOApsXYM.png

在使用行內樣式(Inline Styles)時,你可以使用 TypeScript 來為樣式物件添加型別標註,以確保樣式屬性的正確性。

以下是一個示例:

import React from 'react';

interface MyComponentProps {
  color: string;
  fontSize: string;
}

const MyComponent: React.FC<MyComponentProps> = ({ color, fontSize }) => {
  const divStyle: React.CSSProperties = {
    color: color,
    fontSize: fontSize
  };

  return (
    <div style={divStyle}>
      This is a styled div.
    </div>
  );
};

export default MyComponent;

在這個範例中:

  1. 我們首先定義了 MyComponentProps 接口,它包含了 colorfontSize 兩個屬性,它們的型別分別為字串(string)。
  2. 在組件內部,我們使用了 divStyle 物件來儲存行內樣式。這個物件的型別被指定為 React.CSSProperties,這是 React 提供的一個預定義的型別,用於描述行內樣式的物件。
  3. divStyle 物件中,我們使用 colorfontSize 這兩個屬性,並使用傳入的 colorfontSize 變數作為值。
  4. 最後,在 div 元素上使用 style 屬性來應用這個樣式物件。

這樣,你就可以在 React 組件中使用行內樣式並為其添加型別定義了。如果你有任何其他問題,請隨時告訴我!

用了React.CSSProperties之後
當你要編輯divStyle 這個物件的時候
會自動跟你說有什麼屬性可以用,也會提供相對應的建議

在寫inline style的時候非常方便!
https://ithelp.ithome.com.tw/upload/images/20231003/20135750fAdD8ApncZ.png

useRef & TypeScript

.tsx中,如果使用ref並對ref做操作的話,可能會出現一些type的警告
例如以下的程式碼,出現在.tsx中的話….

function MyComponent() {
  const inputRef = useRef(null);
  const handleClick = () => {
    inputRef.current.focus();
  };
  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};
  • inputRef.cueent可能為null

https://ithelp.ithome.com.tw/upload/images/20231003/20135750q0hITi3O64.png

獲得「可能是null」的警告之後,好那就補個鏈結串鍊
變成 inputRef.current?.focus()

結果第二個問題就又跟著出現了:

  • 類型 never 沒有屬性 focus

https://ithelp.ithome.com.tw/upload/images/20231003/20135750fQ0SOTpSDa.png

讓我們來問問ChatGPT該如何指定Type讓他可以正常運作
https://ithelp.ithome.com.tw/upload/images/20231003/20135750CwvdEK62BZ.png

在使用 useRef 並搭配 TypeScript 撰寫時,你可以首先創建一個 ref 物件,並使用泛型來指定 ref 的型別。以下是一個示例,其中我們創建了一個按鈕,當按下時會將焦點設定到一個 input 元素上:

import React, { useRef } from 'react';

const MyComponent: React.FC = () => {
  // 創建一個 ref,並指定型別為 HTMLInputElement
  const inputRef = useRef<HTMLInputElement | null>(null);

  const handleClick = () => {
    // 使用 ref.current 來訪問 input 元素
    if (inputRef.current) {
      inputRef.current.focus();
    }
  };

  return (
    <div>
      <input ref={inputRef} type="text" />
      <button onClick={handleClick}>Focus Input</button>
    </div>
  );
};

export default MyComponent;

在這個範例中:

  1. 我們使用 useRef 創建了一個 ref 物件 inputRef,並且使用泛型 <HTMLInputElement | null> 來指定它的型別。這表示 inputRef 可以引用一個 HTMLInputElement 或者是 null
  2. 在組件中,我們創建了一個 input 元素,並將 ref 屬性設定為 inputRef,這樣 inputRef 將引用這個 input 元素。
  3. 我們還創建了一個按鈕,並在按鈕的點擊事件處理函數 handleClick 中,我們使用 inputRef.current 來訪問 input 元素,如果存在的話,我們調用 focus() 方法將焦點設定到這個元素上。

這樣,你就可以使用 useRef 來在 React 組件中管理 DOM 元素的引用,並為其添加型別定義。希望這對你有所幫助!如果你有任何其他問題,請隨時告訴我。

這個部分是最困難也最麻煩的的
要放在上時, 要在useRef的泛型中 指定TypeHTMLInputElement

當在的時候呢? 在的時候呢?
問ChatGPT是一個方式,不過這邊分享另外一個小方式

假設要放

  1. 直接在,button元件中新增一個 ref={} 的屬性
  2. 滑鼠移動到{} 中,會跳出該Ref應該要用何種泛型的Ref

https://ithelp.ithome.com.tw/upload/images/20231003/20135750LWeRTJTeM6.png

上面這邊就可以看到,他是<HTMLButtonElement>
所以如果要添加一個Ref在button上的話,他的正確型別就是
useRef<HTMLButtonElement>

總結本篇重點

https://ithelp.ithome.com.tw/upload/images/20231003/20135750hQ1NTF33uG.png

當你在開發 React 應用程式並搭配 TypeScript 時,以下是一些重點:

  1. 在 React 專案中使用 TypeScript
    • 使用 Create React App 來建立新的 React 專案時,可以選擇 TypeScript 作為模板。
    • 如果在已存在的專案中添加 TypeScript,請確保安裝相關的 TypeScript 套件。
  2. Props 的型別定義
    • 使用 interfacetype 來定義 props 的型別。
    • 在函數組件中,可以直接在參數中指定 props 的型別。
  3. 行內樣式 (Inline Styles)
    • 使用 style 屬性在 JSX 元素中直接添加樣式。
    • 使用 React.CSSProperties 來指定樣式物件的型別。
  4. 使用 CSS 檔案
    • 將樣式寫在獨立的 CSS 檔案中,然後在組件中引入。
    • 使用 className 屬性來引用 CSS 中的類別。
  5. 使用 useRef
    • 使用 useRef 來創建一個 DOM 元素的引用。
    • 使用泛型來指定 ref 的型別,例如 useRef<HTMLInputElement | null>(null)

最終,這樣的開發方式將使你能夠以安全、清晰的方式開發 React 應用程式,同時保證程式碼的可靠性和易讀性。

如果你在使用的過程中遇到了任何問題,隨時向我尋求幫助。祝你在前端開發的旅途中順利前行!

結語

搭配TypeScript開發,終於開發時候的安心感又回來了
我個人認為最大的幫助,應該還是Props的型別指定
在使用Component時就不會不知道要如何使用、不小心漏傳屬性,或是傳遞錯誤的型別

這次的對話記錄在這邊:
https://chat.openai.com/share/32a16a20-7a3a-453e-af56-4246df1c3f82

下一篇!仍然是React主題,React x axios !
我是用著TypeScript好安心的前端工程師一宵三筵,我們明天見~


上一篇
【Day20】ChatGPT請教教我:React入門(六)- ref?useRef!forwardRef!useImperativeHandle!
下一篇
【Day22】ChatGPT請教教我:React入門(八)- React & axios !API串起來!
系列文
用ChatGPT詠唱來完成工作與點亮前後端技能樹56
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言