7-2 新增地區設定頁面

本單元對應的專案分支為:create-weather-setting-page

單元核心#

這個單元的主要目標包含:

  • 新增地區設定的頁面

在這個單元中,我們會新增一個頁面來讓使用者調整所在地區。

建立天氣設定頁面:新增 WeatherSetting.js#

現在我們要來建立一個簡單的設定頁面如下圖,順便可以複習一下 Styled Components 的使用。首先在 ./src/views 資料夾中新增一支名為 WeatherSetting.js 的檔案:

imgur

建立 Styled Components#

由於 CSS 樣式部分並不是本書著墨的重點,因此讀者只需在本單元在 Github 上對應的分支(create-weather-setting-page)說明頁,將預先撰寫好的 Styled Components,複製貼上到 ./src/views/WeatherSetting.js

Imgur

撰寫 JSX#

接下來把這些撰寫好的 Styled Components 帶入 JSX 中使用:

// ./src/views/WeatherSetting.js
import React from 'react';
// ...
// Styled Components ...
const WeatherSetting = () => {
return (
<WeatherSettingWrapper>
<Title>設定</Title>
<StyledLabel htmlFor="location">地區</StyledLabel>
<StyledSelect id="location" name="location">
{/* 定義可以選擇的地區選項 */}
</StyledSelect>
<ButtonGroup>
<Back>返回</Back>
<Save>儲存</Save>
</ButtonGroup>
</WeatherSettingWrapper>
);
};

這是一個相當簡單的設定頁面,比較需要留意的地方是:

  1. 在 HTML 的 <label> 中,使用的是 for 屬性,而在 React JSX 中,為了避免和 JavaScript 的 for 關鍵字衝突,因此會使用 htmlFor,例如,<label htmlFor="location">
  2. 在 Input 中使用的是 HTML 的 Select 元素,透過下拉式選單的方式,讓使用者選擇所在的地區

在 Select 中使用迴圈來產生地區選項#

還記得在本書前幾個章節中,曾經有說明過如何在 JSX 中使用迴圈嗎?現在我們一樣要透過迴圈的方式在 <Select /> 中帶入可以讓使用者選擇的地區選項,具體來說,可以使用我們在上一個單元中在 ./src/utils/helpers.js 中定義好的 availableLocations 陣列:

  1. 先把 availableLocations 陣列匯入
// ./src/views/WeatherSetting.js
// ...
import { availableLocations } from './../utils/helpers';
  1. 要帶出 Select 元素中的各個選項,不需要自己一個一個把所有選項打出來,而是可以透過先前學過的「JSX 中迴圈的使用」,把所有可以選擇的地區透過迴圈加以呈現即可:
const WeatherSetting = () => {
return (
// ...
<StyledSelect id="location" name="location">
{availableLocations.map((location) => (
<option value={location.cityName} key={location.cityName}>
{location.cityName}
</option>
))}
</StyledSelect>
);
};

這裡在迴圈(.map)中,同樣也可以透過物件的解構,直接把需要的 cityName 屬性取出,像是這樣:

const WeatherSetting = () => {
return (
// ...
<StyledSelect id="location" name="location">
{availableLocations.map(({ cityName }) => (
<option value={cityName} key={cityName}>
{cityName}
</option>
))}
</StyledSelect>
);
};

透過條件轉譯顯示不同頁面#

在 App 元件中匯入 WeatherSetting 元件#

一直看不到頁面的樣子實在沒什麼安全感,先來看一下剛剛完成的 WeatherSetting 長什麼樣子吧!

首先到 App.js 中透過 importWeatherSetting 元件載入,並且在 JSX 中使用它:

// ./src/App.js
// ...
import WeatherCard from './views/WeatherCard';
import WeatherSetting from './views/WeatherSetting';

接著在 <Container> 中使用 WeatherSetting 元件:

// ./src/App.js
// ...
const App = () => {
// ...
return (
<ThemeProvider theme={theme[currentTheme]}>
<Container>
<WeatherCard
weatherElement={weatherElement}
moment={moment}
fetchData={fetchData}
/>
<WeatherSetting /> {/* 放入 WeatherSetting 元件 */}
</Container>
</ThemeProvider>
);
};

這時候你會看到頁面上同時呈現出 WeatherCardWeatherSetting 這兩個元件:

Imgur

那麼要怎麼讓這兩個元件像是切換頁面一樣呢?其實在前端框架中,使用者畫面上要看到什麼內容,多數都還是使用之前學到的條件轉譯(condition render)在操作,就算未來看到所謂的前端路由(例如,react-router、vue-router),本質上仍然是條件轉譯的應用,但會做到更多不同的功能,讓使用者感覺是在不同網址間切換。

在 App 元件中進行條件轉譯來切換頁面#

現在,在 App 元件中包含了 WeatherCard 和 WeatherSetting 這兩個頁面,因此這裡我們可以在 App 元件中定義一個 state,用這個 state 來決定現在要讓使用者看到哪一個頁面,就讓我們開始吧!

打開 App.js:

  1. 透過 useState,定義 currentPage 這個 state,預設值是 WeatherCard
  2. 透過條件轉譯的方式,使用 && 判斷式來決定要呈現哪個元件在畫面上
// ./src/App.js
const App = () => {
// STEP 1:定義 currentPage 這個 state,預設值是 WeatherCard
const [currentPage, setCurrentPage] = useState('WeatherCard');
return (
<ThemeProvider theme={theme[currentTheme]}>
<Container>
{/* STEP 2:利用條件轉譯的方式決定要呈現哪個元件 */}
{currentPage === 'WeatherCard' && (
<WeatherCard
weatherElement={weatherElement}
moment={moment}
fetchData={fetchData}
/>
)}
{currentPage === 'WeatherSetting' && <WeatherSetting />}
</Container>
</ThemeProvider>
);
};

現在你可以透過 React Developer Tools 來修改 currentPage 的資料狀態,把它從 WeatherCard 改成 WeatherSetting,看看能不能順利切換到不同頁面:

Imgur

在下一個單元中,會再來看怎麼讓使用者透過點擊按鈕進入到設定頁。

換你了!實作天氣設定頁面#

現在要換你實作天氣設定頁面,並且透過條件轉譯的方式,讓使用者一次只會看到一個頁面。同樣可以參考以下步驟:

  • 新增 ./src/views/WeatherSetting.js 檔案
  • 於本單元分支的說明頁,將預先撰寫好的 styled components 複製到 WeatherSetting.js 中
  • 在 WeatherSetting 元件的 JSX 中使用定義好的 styled components
  • ./src/utils/helpers 中匯入 availableLocations 物件,並以迴圈的方式產生 Select 中選項
  • 在 App 元件中匯入 WeatherSetting 元件
  • 在 App 元件中,透過 useState 定義 currentPage,並以條件轉譯的方式分別呈現不同的頁面
  • 使用 React Developer Tools 試著改變 currentPage 的資料狀態,看看畫面會不會有對應的改變

本單元相關之網頁連結、完整程式碼與程式碼變更部分可於 support-dark-theme 分支檢視:https://github.com/pjchender/learn-react-from-hook-realtime-weather-app/tree/create-weather-setting-page

!Imgur