今天要來練習做下拉式選單選擇國家。目前我們的程式碼已經有基礎的樣式。需要讓下拉式選單的功能正常運作。
import React from "react";
import { COUNTRIES } from "./data";
const countriesNames = Object.entries(COUNTRIES);
function App() {
const [country, setCountry] = React.useState("");
return (
<form>
<fieldset>
<legend>Shipping Info</legend>
<label htmlFor="country">Country:</label>
<select
required
id="country"
name="country"
value={country}
onChange={(event) => {
setCountry(event.target.value);
}}>
<option value="">- Select Country -</option>
<optgroup label="Countries">
{countriesNames.map(([id, label]) => {
return (
<option key={id} value={id}>
{label}
</option>
);
})}
</optgroup>
</select>
</fieldset>
<p className="country-display">Selected country: {COUNTRIES[country]}</p>
<button>Submit</button>
</form>
);
}
export default App;
畫面是這樣子:
export const COUNTRIES = {
AF: "Afghanistan",
AL: "Albania",
DZ: "Algeria",
AS: "American Samoa",
//...
};
const countriesNames = Object.entries(COUNTRIES);
//const countriesNames = Object.keys(COUNTRIES);//可以取得國碼
//const countriesNames = Object.values(COUNTRIES);//可以取得值
在 return 的 JSX 當中,使用解構賦值的寫法來分別區分國家碼和國家名稱。
{
countriesNames.map(([id, label]) => {
return <option>{label}</option>;
});
}
在這個步驟,已經初步完成了讓選單內出現了所需要的國家清單。
接著要來處理 state 的部分,可以使用國家的代碼來設定 key 和 value。
<option key={id} value={id}>
在 select 標籤上設定onChange
event prop
<select
id="country"
name="country"
onChange={event=>{
console.log(event.target)
}}
>
在目前event.target
改變觸發的是 HTML element
更進一步改成event.target.value
的話,console.log 的結果則會是國家的代碼。
會有這樣的結果是因為在第三步驟時我們將select
的value
設定為{id}
了。現在當我們選擇該國家
「Selected country」就會顯示該國家相應的代碼。
完成這個步驟看似一切都已經就定位了,真的有需要設定value
嗎?假設不設定 select 標籤的value
屬性好了,當我們將初始值設定為
const [country, setCountry] = React.useState("BZ");
按照邏輯應該要是「Brazil」巴西才對,但結果卻是以下的樣子:
也就是說這樣子的資料流是單向的。可以透過 select 的事件變化來觸發渲染,但卻沒辦法透過 state 來設定初始值。所以value
的設定是必要的,這也是資料綁定(Data-Binding)的概念。所以在這個步驟,我們也應該在 select 標籤上面設定value
。
value = { country };
這邊的 country 也就是在useState
當中的初始值。
接著要來處理預設的畫面,也就是使用者尚未點擊之前,選單需顯示「-Select Your Country-」。可以透過追加一個 option 元素來達成,
<option>-Select Your Country-</option>
這樣子已經有了初始的選項,我們可以追加一些細節讓它更加完善,在 option 元素中添加一個value
的屬性值設定為 empty
並且在 select 元素上設定required
來讓選項設定為必填。這樣使用者如果直接送出表單,那麼便會跳出「Please select an item in the list.」的通知。
<option value="">- Select Country -</option>
再來可以再稍微調整一下使用者體驗的部分,可以使用optgroup
這個標籤來把國家區分開來。
<optgroup>
是 HTML 中的一個標籤,用於在 <select>
元素中組織和分類選項。當你有一個包含多個選項的下拉列表時,有時候希望這些選項被分組顯示,以增加可讀性和組織性。
<optgroup>
可以編輯 label 標籤:
<option value="">
- Select Country -
</option>
<optgroup label="Countries">
{countriesNames.map(
([id, label]) => {
return (
<option
key={id}
value={id}
>
{label}
</option>
);
}
)}
</optgroup>
像這樣把「-Select Country -」和國家列表區隔開來,便可達到這樣子的效果,可以看到灰底的「Countries」區隔了「-Select Country -」和國家清單。
最後一步,黃色的區塊,目前顯示的是所選國家的代碼,這邊若要讓它顯示為所選國家,可以改成以下這樣子:
<p className="country-display">Selected country: {COUNTRIES[country]}</p>
這樣即完成國家列表的下拉式選單了。
以上是今天的練習。