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 ?? b | a 是空的(null・undefined)時就用 b | user.name ?? "訪客" |
| a?.b | 就算 a 是空的也不會出錯,而是得到 undefined | user?.name |
寫法
| 寫法 | 規則(一句話) | 範例 |
|---|
| (x) => … | 建立函式(接收 x,執行 …) | () => setCount(count + 1) |
| (x) => { … } | 裡面可以寫好幾行的函式 | onClick={() => { reset(); setSent(false) }} |
| const 和 let | const 不重新指定,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"
const initialMembers = [
{ id: 1, name: "陳怡君", plan: "付費" },
{ id: 2, name: "林志明", plan: "免費" },
{ id: 3, name: "王雅婷", plan: "付費" },
]
export default function App() {
const [members, setMembers] = useState(initialMembers)
const [paidOnly, setPaidOnly] = useState(false)
const shown = paidOnly ? members.filter((member) => member.plan === "付費") : members
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>
)
}- 按一下「只看付費」(filter 會產生只有付費會員的新陣列)
- 把 "付費" 改成 "免費" 試試看
- 多按幾次「加 1 人」([...members, 新成員] 會在最後一個一個增加)