☕ NEW! 完成新手任務即可參加抽獎!LINE 星巴克禮券等你拿,名額有限!        🎉 推廣活動:邀請好友註冊 DevLearn,累積推薦抽 LINE 星巴克禮券! 活動詳情 →        🔥 活動期間 2026/4/1 - 5/31 |已有 0 人參加       
react 初學

⚛️ React 基礎:useState、Props 與事件處理

📌 函式元件(Function Components)

React 元件就是一個 JavaScript 函式,回傳 JSX 來描述 UI。

⚠️ 再次強調:React 元件不是原生 HTML,JSX 會被編譯成 React.createElement() 呼叫。

// 最簡單的函式元件
function Welcome() {
  return <h1>歡迎使用 React!</h1>;
}

// 箭頭函式寫法(也很常見)
const Welcome = () => <h1>歡迎使用 React!</h1>;

// 使用元件(像 HTML 標籤一樣)
function App() {
  return (
    <div>
      <Welcome />       {/* 使用自訂元件 */}
      <Welcome />       {/* 可以重複使用 */}
    </div>
  );
}

🔄 useState Hook — 狀態管理

useState 讓元件擁有「記憶」——能記住並更新資料。

import { useState } from 'react';

function Counter() {
  // useState 回傳 [目前的值, 更新函式]
  const [count, setCount] = useState(0);  // 初始值 = 0

  return (
    <div>
      <p>目前計數:{count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
      <button onClick={() => setCount(count - 1)}>-1</button>
      <button onClick={() => setCount(0)}>歸零</button>
    </div>
  );
}

💡 為什麼不能直接 count = count + 1 React 只在呼叫 setCount 時才知道要重新渲染。 直接修改變數不會觸發 UI 更新——這是 React 與原生 JS 最大的差異之一。

物件與陣列狀態

function UserForm() {
  const [user, setUser] = useState({ name: '', age: 0 });

  // ⚠️ 必須展開原物件,React 靠「新參考」判斷是否更新
  const updateName = (e) => {
    setUser({ ...user, name: e.target.value });  // 展開運算子
  };

  return (
    <input value={user.name} onChange={updateName} />
  );
}

📦 Props — 父元件傳資料給子元件

Props 是元件之間溝通的方式,像函式的參數一樣。

// 子元件:接收 props
function UserCard({ name, age, isActive }) {
  return (
    <div className={`card ${isActive ? 'active' : ''}`}>
      <h2>{name}</h2>
      <p>年齡:{age}</p>
      <span>{isActive ? '🟢 上線' : '🔴 離線'}</span>
    </div>
  );
}

// 父元件:傳遞 props
function App() {
  return (
    <div>
      <UserCard name="小明" age={25} isActive={true} />
      <UserCard name="小華" age={30} isActive={false} />
    </div>
  );
}

⚠️ Props 是唯讀的! 子元件不能修改收到的 props。 如果需要改變資料,應該由父元件透過回呼函式處理。


🖱️ 事件處理

React 事件用 camelCase 命名(onClick 而非 onclick),傳入的是函式而非字串。

function EventDemo() {
  // 點擊事件
  const handleClick = () => {
    alert('按鈕被點擊了!');
  };

  // 輸入變更事件
  const [text, setText] = useState('');
  const handleChange = (e) => {
    setText(e.target.value);    // e.target.value 取得輸入值
  };

  // 表單送出事件
  const handleSubmit = (e) => {
    e.preventDefault();          // 阻止表單預設送出行為
    console.log('提交的文字:', text);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        value={text}
        onChange={handleChange}
        placeholder="輸入文字..."
      />
      <button type="submit">送出</button>
      <button type="button" onClick={handleClick}>點我</button>
    </form>
  );
}

💡 React 事件 vs 原生 JS 事件

  • 原生:element.addEventListener('click', handler)
  • React:<button onClick={handler}>(宣告式,更直覺)
  • React 使用 合成事件(SyntheticEvent),跨瀏覽器一致。

🔀 條件渲染

function StatusMessage({ isLoggedIn, username }) {
  // 方法一:三元運算子
  return (
    <div>
      {isLoggedIn ? (
        <p>歡迎回來,{username}!</p>
      ) : (
        <p>請先登入</p>
      )}

      {/* 方法二:&& 短路求值 */}
      {isLoggedIn && <button>登出</button>}
    </div>
  );
}

📋 列表渲染

function TodoList() {
  const [todos, setTodos] = useState([
    { id: 1, text: '學習 React', done: false },
    { id: 2, text: '寫元件', done: true },
    { id: 3, text: '部署應用', done: false },
  ]);

  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, done: !todo.done } : todo
    ));
  };

  return (
    <ul>
      {todos.map(todo => (
        <li
          key={todo.id}                    // ⚠️ key 是必要的!
          onClick={() => toggleTodo(todo.id)}
          style={{ textDecoration: todo.done ? 'line-through' : 'none' }}
        >
          {todo.text}
        </li>
      ))}
    </ul>
  );
}

⚠️ key 的重要性: React 用 key 來追蹤列表中的每個項目。沒有 key 或用 indexkey 可能導致效能問題和 bug。


🛠️ 完整範例:計數器 + 待辦清單

import { useState } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const [input, setInput] = useState('');
  const [todos, setTodos] = useState([]);

  const addTodo = () => {
    if (input.trim() === '') return;
    setTodos([...todos, { id: Date.now(), text: input, done: false }]);
    setInput('');                    // 清空輸入
    setCount(count + 1);            // 計數器加 1
  };

  return (
    <div style={{ padding: '20px' }}>
      <h1>已新增 {count} 個待辦</h1>

      <input
        value={input}
        onChange={(e) => setInput(e.target.value)}
        onKeyDown={(e) => e.key === 'Enter' && addTodo()}
        placeholder="輸入待辦事項..."
      />
      <button onClick={addTodo}>新增</button>

      <ul>
        {todos.map(todo => (
          <li key={todo.id}>{todo.text}</li>
        ))}
      </ul>
    </div>
  );
}

✅ 本章重點

觀念 說明
函式元件 回傳 JSX 的函式,大寫開頭
useState 狀態管理 Hook,更新觸發重新渲染
Props 父傳子的唯讀資料
事件處理 camelCase、傳入函式、合成事件
條件渲染 三元運算子、&& 短路
列表渲染 .map() + key

💡 大家的想法 · 0

載入中...
💬 即時聊天室 🟢 0 人在線
😀 😎 🤓 💻 🎮 🎸 🔥
➕ 新問題
📋 我的工單
💬 LINE 社群
🔒
需要註冊才能使用此功能
註冊帳號即可解鎖測驗、遊戲、簽到、筆記下載等所有功能,完全免費!
免費註冊