昨天我們的專案文件大概如下
.
├── README.md
├── package-lock.json
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── DialogueComponentes
│ │ ├── DialogueBox.tsx
│ │ └── type.tsx
│ ├── index.css
│ ├── index.tsx
│ ├── logo.svg
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ └── setupTests.ts
└── tsconfig.json
昨天我們創建了兩個檔案 DialogueBox.tsx
和 type.tsx
,會發現DialogueBox.tsx
處理的事項好像有點雜亂,這時我們可以進行分開,讓一個 Dom 只處理一件事情,例如將 DialogueBox.tsx
拆分成 UI 和 對話邏輯,為此我會建立一個新的檔案叫做 DialogueManager.tsx
來處理對話邏輯而DialogueBox.tsx
專心處理呈現的方式即可。另外一件事情就是我會使用 type.tsx
內的 DialogueProps 變數,作為我傳遞資訊的用途。
首先在 dialogue-project/src/
下建立一個 DialougueComponent
的資料夾。並建立新檔案 DialogueManager.tsx
。
DialogueBox.tsx
:用於顯示對話的視窗。type.tsx
:用於定義型別。DialogueManager.tsx
:用於處理對話過程。小心檔案名稱不要取名為
ts
了,我們需要取名為tsx
這樣才能讓 TypeScript 吃到 JSX 的語法。(JSX 可以讓 JavaScript 內吃到 XML/HTML 語法)
// DialogueManager
import React, { useState } from 'react';
import { European, Asian, Person } from './type';
import DialogueBox from './DialogueBox';
const DialogueManager: React.FC = () => {
const peter = new European("Peter", ["你好!", "歐洲真的很美!", "我們一天只要上五小時的班。"]);
const lee = new Asian("Lee", ["嗨!", "真的嗎?那真的太棒了!", "Emotional damage, 受到 1000000 點傷害 QQ"]);
const combinedDialogues: { person: Person, text: string }[] = [];
for(let i = 0; i < Math.max(peter.dialogues.length, lee.dialogues.length); i++) {
if (peter.dialogues[i]) {
combinedDialogues.push({ person: peter, text: peter.dialogues[i] });
}
if (lee.dialogues[i]) {
combinedDialogues.push({ person: lee, text: lee.dialogues[i] });
}
}
const [currentDialogueIndex, setCurrentDialogueIndex] = useState<number>(0);
const proceedToNextDialogue = () => {
setCurrentDialogueIndex(prevIndex => prevIndex + 1);
};
return (
<DialogueBox
dialogue={combinedDialogues[currentDialogueIndex]}
onNext={proceedToNextDialogue}
isEnd={currentDialogueIndex >= combinedDialogues.length}
/>
);
};
export default DialogueManager;
將原先 DialogueBox.tsx
上的繁雜運算過程,搬移至 DialogueManager.tsx
上,並透過 Props 進行資料上的傳遞。
// DialogueBox
import React from 'react';
import { DialogueProps } from './type';
const DialogueBox: React.FC<DialogueProps> = ({ dialogue, onNext, isEnd }) => {
return (
<div>
{!isEnd ? (
<div>
<p> {dialogue.person.name}: {dialogue.text} </p>
<button onClick={ onNext }>Next</button>
</div>
) : (
<div> <p>End of the dialogue.</p></div>
)}
</div>
);
};
export default DialogueBox;
將 DialogueBox.tsx
修改成專注於 UI 呈現上,並透過父組件( DialogueManager.tsx
)傳遞來的資料進行畫面切換。
// type.tsx
export type DialogueProps = {
dialogue: { person: Person, text: string };
onNext: () => void;
isEnd: boolean;
};
export type Person = {
name: string;
dialogues: string[];
};
export class European implements Person {
constructor(public name: string, public dialogues: string[]) {}
}
export class Asian implements Person {
constructor(public name: string, public dialogues: string[]) {}
}
開始使用之前的定義好的 DialogueProps
並把參數決定好。
// app.tsx
import React from 'react';
import DialogueManager from './DialogueComponentes/DialogueManager';
const App: React.FC = () => {
return (
<div className="App">
<DialogueManager />
</div>
);
}
export default App;
在 app.tsx
上更改呼叫為 DialogueManager
。接下來在專案底下運行指令 npm start
就可以看到跟之前一樣的效果。
至此,我們成功地完成了一個 React 的小專案。從這個專案,不僅可以看到React的強大,還能夠深刻體會到 React 在前端開發中的便捷性。從組件的拆分、State 的管理到 Props 的傳遞,每一步都讓我對 React 的概念有了更深入的理解。總之,完成這個小專案只是我學習的開始,接下來,我們還有更多的 TypeScript 知識需要去探索和學習。 希望最後能完成另一個小專案。