JavaScript 基礎

只講 React 程式碼裡常見的 JavaScript

重點

  • 在 React 裡卡住的地方,大多不是 React,而是 JavaScript。這裡分成陣列函式、比較符號、寫法三類整理
  • map、filter、...(展開)不會修改原本的陣列,而是產生「新的陣列」。所以和 React 的 state 很合得來
  • 遇到不認識的寫法,先讀下表裡一句話的「規則」,再到示範裡試試看

速查表

陣列的函式

寫法規則(一句話)範例
.map((x) => …)一個一個取出,產生變換後的新陣列members.map((m) => <li>{m.name}</li>)
.filter((x) => 條件)產生只留下符合條件項目的新陣列members.filter((m) => m.plan === "付費")
.find((x) => 條件)回傳第一個符合條件的項目members.find((m) => m.id === 2)
.sort((a, b) => 數字)兩兩比較來排序。結果是負數時 a 排在前面[...items].sort((a, b) => a.price - b.price)
.slice(開始, 結束)從開始切到結束的前一個(從 0 開始數)items.slice(0, 6)
.reduce((合計, x) => …, 0)一個一個看,整合成一個值(例如合計)items.reduce((sum, i) => sum + i.price, 0)
.includes(x)是否包含 x(true/false)name.includes(query)
.length陣列是項目數,字串是字數{members.length} 人
.some((x) => 條件)是否至少有一個符合條件(true/false)items.some((i) => i.stock === 0)
.join(分隔符號)把陣列用分隔符號串成一個字串tags.join("、")

比較與連接

寫法規則(一句話)範例
===左邊和右邊是否相同plan === "付費"
!==左邊和右邊是否不同m.id !== id
> >= < <=大於・大於等於・小於・小於等於quantity >= stock
!變成相反(true ↔ false)!isOpen
&&而且。在 JSX 中表示「符合就顯示」{error && <p>{error}</p>}
||或者!isDirty || isSubmitting
條件 ? A : B符合就是 A,不符合就是 B{open ? "關閉" : "打開"}
a ?? ba 是空的(null・undefined)時就用 buser.name ?? "訪客"
a?.b就算 a 是空的也不會出錯,而是得到 undefineduser?.name

寫法

寫法規則(一句話)範例
(x) => …建立函式(接收 x,執行 …)() => setCount(count + 1)
(x) => { … }裡面可以寫好幾行的函式onClick={() => { reset(); setSent(false) }}
const 和 letconst 不重新指定,let 之後可以重新指定let sorted = filtered
const [a, setA] = …替回傳的兩個值取名並取出const [count, setCount] = useState(0)
const { a, b } = …從物件({ })裡依名字只取出要用的部分const { user } = useAuth()
function X({ a })依名字接收傳給元件的值(props)function Card({ title }) { … }
`…${x}…`在字串裡放入值(樣板字串)`${count} 筆`
[...x, 新增]複製陣列,並在最後加上新項目的新陣列setMembers([...members, newMember])
{ ...x, 鍵: 值 }複製一個物件,只改一個地方的新物件{ ...member, id: 7 }
import/export使用其他檔案的元件/提供給其他檔案使用import { Button } from "./button"
async/await等待需要時間的事(例如取得資料)完成const res = await fetch(url)

動手試試

import { useState } from "react"

// 會員列表(最初的 3 人)
const initialMembers = [
  { id: 1, name: "陳怡君", plan: "付費" },
  { id: 2, name: "林志明", plan: "免費" },
  { id: 3, name: "王雅婷", plan: "付費" },
]

export default function App() {
  // 會員列表(按「加 1 人」會增加)
  const [members, setMembers] = useState(initialMembers)
  // 是否按下了「只看付費」(true = 已按下)
  const [paidOnly, setPaidOnly] = useState(false)

  // 要顯示的列表:按下了就只顯示付費會員,沒按就顯示全部
  const shown = paidOnly ? members.filter((member) => member.plan === "付費") : members

  // 加 1 人:把現有會員全部排好,在最後加上 1 位新會員
  function addMember() {
    const newId = members.length + 1
    setMembers([...members, { id: newId, name: "會員" + newId, plan: "免費" }])
  }

  return (
    <div style={{ padding: 16, fontFamily: "sans-serif" }}>
      <div style={{ display: "flex", gap: 8 }}>
        {/* 每按一次,就在 只看付費 ↔ 全部 之間切換(! = 變成相反) */}
        <button onClick={() => setPaidOnly(!paidOnly)}>{paidOnly ? "查看全部" : "只看付費"}</button>
        <button onClick={() => addMember()}>加 1 人</button>
      </div>
      <p>共 {shown.length} 人</p>
      {/* 把要顯示的列表,一個一個變成「名字(方案)」的一行 */}
      <ul>
        {shown.map((member) => (
          <li key={member.id}>
            {member.name}({member.plan})
          </li>
        ))}
      </ul>
    </div>
  )
}
  1. 按一下「只看付費」(filter 會產生只有付費會員的新陣列)
  2. 把 "付費" 改成 "免費" 試試看
  3. 多按幾次「加 1 人」([...members, 新成員] 會在最後一個一個增加)

常見錯誤

用 members.push(人) 畫面不會變
push 只是改寫原本的陣列,React 察覺不到變化。要用 [...members, 人] 產生新陣列,再傳給 setMembers。
.sort 會改寫原本的陣列
和 map、filter 不同,sort 會直接把原本的陣列重新排序。要像 [...items].sort(…) 這樣,先複製再排序。
= 是「放進去」,=== 是「是否相同」
如果在條件裡寫 =,不會比較,而是把值放進去。比較時要用 ===。