建立元件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const Card = ({ title, price, content, callToAction } ) => { return ( <div className ="card mb-4" > <div className ="card-header" > <h4 className ="my-0" > {title}</h4 > </div > <div className ="card-body" > <h1 className ="card-title" > { typeof price === 'number' ? `$${price}`: price } </h1 > <p > {content}</p > <button type ="button" className ="btn btn-outline-primary" > {callToAction} </button > </div > </div > ) }
上面是一個卡片元件,React 元件必須以大寫開頭命名。卡片的內的資料可以透過 props 傳入,上面是透過解構的方式傳入 props 。如果不透過解構則會如下面方式取得資料。
1 2 3 const Card = (props ) => { { props.title } }
結構只有一行時,可以直接 return
1 return <img src ="https://i.imgur.com/MK3eW3As.jpg" alt ="Katherine Johnson" /> ;
結構超過一行,必須加上 ()
1 2 3 4 5 return ( <div > <img src ="https://i.imgur.com/MK3eW3As.jpg" alt ="Katherine Johnson" /> </div > );
父層傳入資料 在父層可透過資料驅動的方式,將資料代入子層 Card 元件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 const App = ( ) => { const products = [ { id : 1 , title : '基本版' , price : 1000 , content : '基本每週配給,包含高麗菜、空心菜,健康不馬乎' , callToAction : '免費試用' , }, { id : 2 , title : '進階版' , price : 6000 , content : '奶蛋魚肉經營養師精確估計,適合三人小家庭使用,每週一、四配送' , callToAction : '永保健康' , }, { id : 3 , title : '企業版' , price : '請洽客服' , content : '多少人數均可訂製,5 ~ 1000 人團體均適用' , callToAction : '大吃大喝方案' , }, ]; return ( <> <h2 > 月月送菜到你家</h2 > <p > Lorem ipsum dolor sit amet</p > { products.map((product) => { return <Card key ={product.id} title ={product.title} price ={product.price} content ={product.content} callToAction ={product.callToAction}/ > }) } </> ) }
上面將 products 陣列資料透過 map 的方式一一渲染到畫面,並將每筆 product 資料帶入 Card 元件內。
使用 key 值 當渲染陣列資料時,要在每個元件代入 key 值,並且 key 值要是唯一值。
提升渲染效能: 當你渲染一組列表時,key 幫助 React 快速判斷哪些元素需要更新、刪除或重新排序。這比每次重新渲染整個列表要高效得多。例如,如果你有一個包含多個項目的待辦事項列表(To-Do List),當你新增一個項目時,React 會利用 key 來只更新新增的部分,而不是重新渲染整個列表。
保持元件狀態的一致性: 唯一的 key 可以確保元件在更新時保持狀態的一致性。舉個例子,假設你有一個可以打勾完成的待辦事項列表,如果每個項目沒有唯一的 key,當你刪除其中一個項目時,React 可能會誤解為其他項目發生了變動,導致狀態錯亂。
避免潛在的錯誤: 如果沒有提供唯一的 key,或是 key 不是唯一的,React 會發出警告,提醒你可能會導致渲染問題或效能問題。這時候,你可能會遇到列表項目顯示不正確、狀態錯誤等問題。
迴圈一次帶入多個 dom 使用 map 將資料渲染到畫面時,若 dom 結構不只一個,可以用 <Fragment></Fragment>
包起來
1 2 3 4 5 6 7 8 import { Fragment } from 'react' ;const listItems = people.map (person => <Fragment key ={person.id} > <h1 > {person.name}</h1 > <p > {person.bio}</p > </Fragment > );
props 預設值 元件接收父層傳入的 props 時,也可設定預設值:
當父層沒有傳入值,或是傳入的是 size={ undefined }
時使用預設值。
傳入的是 size={null} or size={0}
,不會使用預設值
1 2 3 function Avatar ({ person, size = 100 } ) { }
不要在 state 中鏡像(mirror)props 初學者經常會將從 props 傳來的資料複製到 state 中,這樣看似可以讓組件本地化管理資料,但實際上這樣會導致資料不一致。
錯誤範例: 1 2 3 4 5 6 7 8 9 function UserProfile ({ name } ) { const [userName, setUserName] = useState (name); useEffect (() => { setUserName (name); }, [name]); return <h1 > {userName}</h1 > ; }
正確做法 1 2 3 function UserProfile ({ name } ) { return <h1 > {name}</h1 > ; }
巢狀元件 元件本身也可以帶入其他元件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const PrimaryButton = ({ className, callToAction } ) => { return <button type ="button" className ={ `btn ${className }`}> {callToAction}</button > } const Card = ({title, price, content, callToAction} ) => { return (<div className ="card mb-4" > <div className ="card-header" > <h4 className ="my-0" > {title}</h4 > </div > <div className ="card-body" > <h1 className ="card-title" > {typeof price === 'number' ? <> <small > ${price} / 月</small > </> : price }</h1 > <p > {content}</p > { title === '企業版' ? <PrimaryButton className ="btn-primary" callToAction ={callToAction}/ > : <PrimaryButton className ="btn-outline-primary" callToAction ={callToAction}/ > } </div > </div>) }
上面 Card 元件內帶入了 PrimaryButton 的元件。
Children props 除了用 props 將資料帶入元件,也可以用 children 將整個 html 結構代入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const PrimaryButton = ({ className, children } ) => { return <button type ="button" className ={ `btn ${className }`}> {children} </button > } const Card = ({title, price, content, callToAction} ) => { return (<div className ="card mb-4" > <div className ="card-header" > <h4 className ="my-0" > {title}</h4 > </div > <div className ="card-body" > <h1 className ="card-title" > {typeof price === 'number' ? <> <small > ${price} / 月</small > </> : price }</h1 > <p > {content}</p > { title === '企業版' ? <PrimaryButton className ="btn-primary" > <i className ="bi bi-gem" > </i > { callToAction } </PrimaryButton > : <PrimaryButton className ="btn-outline-primary" > { callToAction } </PrimaryButton > } </div > </div>) }
在 PrimaryButton 元件內加入 html 結構,並用 children 將結構代入元件內。
pops 更新時,自動更新元件內所有狀態 1 2 3 4 5 6 7 8 9 10 11 12 13 14 export default function ProfilePage ({ userId } ) { return ( <Profile userId ={userId} key ={userId} /> ); } function Profile ({ userId } ) { const [comment, setComment] = useState ('' ); }
在 React 中,key 屬性用於識別哪些組件需要重新渲染或更新。它為每個組件實例提供了一個唯一的標識。當 userId 改變時,因為 key 也隨之改變,React 會重建 Profile 元件,從而重置元件內的所有狀態(如 comment)。
如果不加 key,當 userId 改變時,會發生以下情況:
React 會認為這是同一個 Profile 組件實例,因此不會重新創建該組件。結果是:
狀態不會重置:組件內的狀態(如 useState 的 comment)將保持不變。
副作用不會重新執行:如果有使用 useEffect 的副作用,也不會因為 userId 改變而重新執行,除非 useEffect 的依賴陣列包含 userId。