iT邦幫忙

2025 iThome 鐵人賽

DAY 30
0
Modern Web

Angular、React、Vue 三框架實戰養成:從零打造高品質前端履歷網站系列 第 30

Day 30 React 完成版 – Projects 篩選互動 + 三框架總結

  • 分享至 

  • xImage
  •  

今日目標

  • 在 Projects 加入 搜尋框只看精選
  • useState 管理條件、即時過濾 view
  • 完成 React 版履歷網站
  • Angular / Vue / React 三框架的比較與心得

1. 改寫 Projects 元件

src/components/Projects.tsx

import React, { useState, useMemo } from 'react'
import type { Project } from '../data/projects'

type Props = {
  items: Project[]
}

export default function Projects({ items }: Props) {
  const [onlyFeatured, setOnlyFeatured] = useState(false)
  const [keyword, setKeyword] = useState('')

  // 過濾邏輯
  const view = useMemo(() => {
    const kw = keyword.toLowerCase()
    return items.filter(p => {
      const matchFeatured = !onlyFeatured || p.featured
      const matchKeyword =
        !kw ||
        p.title.toLowerCase().includes(kw) ||
        p.tech.toLowerCase().includes(kw) ||
        p.desc.toLowerCase().includes(kw)
      return matchFeatured && matchKeyword
    })
  }, [items, onlyFeatured, keyword])

  return (
    <section id="projects" className="container section">
      <h2>作品集 Projects</h2>

      <div style={{ margin: '12px 0', display: 'flex', gap: '12px', alignItems: 'center' }}>
        <label>
          <inputtype="checkbox"
            checked={onlyFeatured}
            onChange={(e) => setOnlyFeatured(e.target.checked)}
          />{' '}
          只看精選
        </label>
        <inputtype="text"
          value={keyword}
          onChange={(e) => setKeyword(e.target.value)}
          placeholder="搜尋關鍵字"
          style={{ flex: 1, maxWidth: '260px' }}
        />
        <small className="muted">{view.length} / {items.length}</small>
      </div>

      <div className="project-grid">
        {view.map((p) => (
          <article className="card" key={p.id}>
            <h3>{p.title}</h3>
            <p className="muted">{p.tech}</p>
            <p>{p.desc}</p>
            <div style={{ display: 'flex', gap: '8px', marginTop: '8px' }}>
              {p.demo && <a className="btn small" href={p.demo} target="_blank">Demo</a>}
              <a className="btn small btn-outline" href={p.repo} target="_blank">GitHub</a>
            </div>
          </article>
        ))}
      </div>
    </section>
  )
}


2. 成果檢查清單 ✅

  • 頁面能輸入關鍵字,動態過濾 Projects
  • 勾「只看精選」,只顯示 featured: true 的項目
  • 計數器顯示「目前結果 / 總數」
  • 完成一個功能完整的 React 版履歷網站 🎉

3. 三框架比較

Angular

  • 優點:結構完整、內建 Router / Form / Http / DI,適合大型專案
  • 缺點:上手門檻高、樣板語法較重
  • 學到:完整體驗大型框架的「一條龍生態系」

Vue

  • 優點:語法直觀、模板友好、社群生態完整(Vue Router / Pinia)
  • 缺點:生態分散,需要挑選方案
  • 學到:單檔 .vue 元件開發體驗佳,資料綁定與響應式很直覺

React

  • 優點:JSX 靈活、Hook 系統強大、NPM 生態最豐富
  • 缺點:很多東西要靠第三方(Router, State, Form)
  • 學到:思維更貼近「函式式程式設計」,元件就是函式

4. 心得收尾 ✨

到這裡,三個框架我們都用來實作了 同一個履歷網站,這有幾個意義:

  1. 比較差異:同一功能在 Angular / Vue / React 寫法不同,讀者能直觀感受。
  2. 展示成果:履歷上可以附三個版本的網站連結,超加分!
  3. 強化心法:前端框架不只是工具,背後的思維方式更重要。

小心踩雷

  1. useState 與即時輸入卡頓
    • 如果過濾邏輯重,可加 debounce(useEffect + setTimeout)。
  2. Props 沒有型別
    • 在 TS 專案一定要明確定義 Props,避免後續維護困難。
  3. 過度複製程式
    • 若三框架都要維護,盡量把資料格式統一(skills.json, projects.json),減少重複。

🎉 系列結束 🎉

恭喜!30 天你完成了:

  • HTML / CSS / TypeScript 基礎
  • Angular 版履歷網站(完整觀念)
  • Vue 版履歷網站(響應式 + 狀態管理 + 部署)
  • React 版履歷網站(JSX + Hooks + 狀態驅動 UI)
  • 三框架完整比較與心得

上一篇
Day 29 React 資料化 – 用 Props 與 useState 管理 Skills 與 Projects
系列文
Angular、React、Vue 三框架實戰養成:從零打造高品質前端履歷網站30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言