---
tags: 上課筆記 - 二十一周到結束
---
# [week 21] - 1:React (創建環境、CSS 跟 component、styled component)
來吧!前端框架
## 課程簡介:
React 官方是說自己是 Library ,只是我們在使用的時候會搭配其他 Library 一起使用,完整性就堪比框架哦!
## 關鍵字:
- component
核心概念
- state 狀態 (重要)
React 的核心概念之一 component
要寫出 component 有兩種方式,一種是透過 class,一個是透過 function
兩者分別叫做 class component 跟 function component
原本早期的版本 function component 不能有 state(狀態)
但是後來 2019/02 出了 v16.8 版本,新增了 hooks ,使 function component 也能擁有 state
這改變了 React 現在這個當下的寫法,現在 2021/09/03 這個當下,很多新的 app 都是用 function componet + hooks 開發。
Huli 建議直接從 function component 開始學
=> [FE302]
class component 有興趣或是 function component 卡住可以回去看。
正式開始:
# [FE302] React 基礎 - hooks 版本
# 先別急著學 React
## 從 Todo list 開始吧!
## 初次認識 Component
React 裡面最重要的概念
Component 元件、組件
在網頁開發的角度,就很像在切版

如果依照 Todo 來看
就會有 title 的 Component
新增的 Component
顯示的 Component
每個 Component 代表它是自成其中一個功能的區塊
底下也可以分成小的 Component

可以切很細、也可以切很粗,但重點是要考慮到 Component 的重用性!
像是 bootstripts 就把 Component 切到像是 button alert 之類的小組件,因為它可以重用,所以它是個 Component
其實在寫 HTML 也算是一個 Component
## 資料 vs 畫面
前幾章可以試著跟著做做看!
在做任何改變的時候同時改資料及畫面

這樣個方式有一種壞處,如果同時改的時候有哪邊沒改到,可能會資料畫面不一致
解決方法兩種 =>
1. 畫面歸畫面,需要資料的時候在即時的去拿出現在資料
2. 新增修改時只更改資料,畫面都是依據資料 render 出來的

這個就是 React 第二個最重要的觀念
畫面永遠都由 state 產生!

## **畫面永遠都由 state 產生**
每次更新都是把畫面重新清空再開始
render,render 就負責把 state 轉化成 UI
所以畫面和 UI 一定會是一致的
**超級模組化**
React 要你去改資料,再改畫面
但是這樣的方式,只要一改資料就把畫面重新清空,改變 state 就清空畫面重新依照 state render
這樣的確是最慢的方式
But React 厲害的地方就是處理了這個問題,比較了新舊 state 的差別,只去新增、修改、刪除等 「必要的部分」
---
本章的範例介紹的寫法使得State 跟 UI 永遠是同步的
有先看過這種寫法擁有這種概念就可以比較快的學習 React
---
React 最核心的概念:
1. Component 元件、組件
把畫面看成、切成幾個 Component ,在實作時就可以把它切開
使 Component 的重用性增加
Component 會接受一些參數叫做 props,props 就可以決定不同的 props 要回傳甚麼東西,可以想像就是 function 的參數啦!
2. 畫面永遠由 State 產生
不會直接改到畫面,都會改資料改 state 在渲染成畫面
上面用 TodoList 介紹了 React 最重要的觀念
## 初探 React
>A JavaScript library for building user interfaces
>用來實作使用者介面的 JavaScript 函式庫
>上面兩行官方簡介,意思 Javascript library,然後是用來處理 UI 的
>自稱 Javascript Library,但 React
提供的整套思維邏輯及寫法,再搭配其他 Library ,其實寫起來算是一個框架。
本節教學 React 17 (2020)
[React](https://zh-hant.reactjs.org/)
學工具就是用就對了!
codesandbox (建立好環境的 codepen)
很常用來建好本地端的環境跟他人討論 debug
用來重現 bug 的環境請人 debug XD
[第一個範例 in codesandbox!](https://codesandbox.io/s/fe302-ce-shi-qhlko)
# React 基礎
## 環境建置:create-react-app
>React 環境建置
環境建置分兩種
1. 從頭做 => webpack、babel ...等等等
2. 用現成的 => 直接下載建置好的環境
這邊用現成的
[建立全新的 React 應用程式](https://zh-hant.reactjs.org/docs/create-a-new-react-app.html)
`npx create-react-app my-app`
- 這樣就會建立一個叫做 <my-app> 的資料夾,可以使用 React
老師的課程 create-react-app 4.0 + React v17.0
v16.8 開始有 hook,大家開始主要使用 function component
簡介:
- `npm run start` 會在本地端跑一個 Server 起來,就可以在這裡寫 React 的東西
預設是跑在 localhost:3000

跑起來囉~
---
看專案的第一件事
看 README
看 JS 專案的第一件事
看 package.json
看 src 裡的 index.js
---
可以看到 index.js 裡面有一個 <React.StrictMode> 也就是嚴格模式
[官方 - 嚴格模式](https://zh-hant.reactjs.org/docs/strict-mode.html)
用這個包裝起來的話,會開啟嚴格模式,可以幫忙檢查是不是有加上其他不該加的東西
但有時候會有 bug,為了檢查可能會 render 兩次, console 可能會有問題,所以先不要用
還有預設 eslinet 哦
可以用 props 或是解構語法接收參數
- React 裡面的 style 寫法
命名名稱不同 `text-align` => `textAlign`
```javascript
const titleStyle = {
color: 'red',
textAlign: 'center'
}
```
## 初探 React 中的 style
>完整介紹 React 中的 style,如何在 React 裡面寫 CSS
### 先講結論
React 中寫 Style => 介紹 JSX
- JSX 中的 class 要怎麼寫?
- inline style - 第一堂課
- className - 以前常用
- styled component - 寫 React 推薦
styled component 推薦用這套寫 CSS ,更推薦去看完官方文件上面的說明,畢竟是工具,這個說明書真的值得看,看 Basics !
### 1. 最直接的方式
一般在 component 裡面寫 CSS 的方式
```javascript
帥氣的直接寫在裡面,看起來就是兩個大括號
function Title({ size }) {
if (size ==='XLL') {
return <h1>XLL Title</h1>
}
return (
<h3 style={{
color: '#ffff78',
textAlign: 'center'
}}>Normal Title</h3>
)
}
```
這種寫法可以支援 CSS 的基本寫法。
但是不支援像是偽元素、hover 等等的寫法
**只支援 inline-style**
這邊很像在 HTML 的第一堂課一樣,寫 CSS 最先介紹的就是 inline-style
所以其他寫法也可想而知的是 class 的 className 寫法
### 2. class name 寫法 => className
這邊要注意在 JXS 的語法裡面,`class` 是保留字,所以要用 `className`
```javascript
function App() {
return (
<div className="App">
</div>
);
}
import './App.css'; // 搭配引入
/ /App.css
.App {
text-align: center;
}
```
這是第二種,可以想像就是一般在用 class 的作法
要注意的是引入不要寫錯
也可以換成 SASS 等等,改 webpack 的設定就好
最後的是最推薦的寫法 styled component
### 3. styled component
下載:[styled-components- Installation](https://styled-components.com/docs/basics#installation)
`npm install --save styled-components` 下載!
說明文件:[styled-components - Basics](https://styled-components.com/docs/basics)
styled component 推薦用這套寫 CSS ,更推薦去看完官方文件上面的說明,畢竟是工具,這個說明書真的值得看,看 Basics !
用法如下

這種寫法也會用到我們熟悉的 template string,就是數字 1 做邊的那個點點 `「``」`
`「``」` 這個東西除了用在 template string 以外,還有另一種用途是用在 function call 裡面
叫做 => tagged template literals
PJ 大大文章 [[筆記] JavaScript ES6 中的模版字符串(template literals)和標籤模版(tagged template)](https://pjchender.blogspot.com/2017/01/javascript-es6-template-literalstagged.html)
- 總之 styled component 就是利用上述的 標籤模版 方法建立了一套寫 CSS 的方法
以下開始示範 styled component
### 3. styled component 簡單示範 - 1 / 3
```javascript
const Description = styled.p`
color: #82ada9;
padding: 20px;
border: 1px solid black;
`
function App() {
return (
<div className="App">
<header className="App-header">
<Description>
哈囉你好嗎
衷心改謝
珍重再見
期待再相逢
</Description>
</header>
</div>
);
}
```
可以看做 `Description` 就是一個有了這些 style 的 `<p>` 的 compontent!(請先學方法就好,原理丟掉)

這邊可以注意的是 class name 的名稱是由 styled component 產生的像是亂碼的東西。

styled component 的原理是我們這樣子做之後,它就動態產生一個 class name,然後幫你把 class name 放在 `Description` 這個元件上面,最後幫你產生 CSS
```javascript
// 設置好 TitleWrapper 這個 component
const TitleWrapper = styled.h2`
display: flex;
color: #ffff78;
&:hover {
color: red;
}
span {
color: pink;
}
`
// 在 Title 這個 component 引入 TitleWrapper 這個 component
function Title({ size }) {
return (
<TitleWrapper>Normal Title<span>Ispan</span></TitleWrapper>
)
}
// 這邊再引入 Title 這個 component
function App() {
return (
<div className="App">
<header className="App-header">
<Title />
<Title size="M" />
</header>
</div>
);
}
```
這樣就有 CSS 效果囉,hover 的功能也有做出來

就是把它當成是一個 component 來用就可以了
### 3. styled component 簡單示範 todo - 2 / 3
這邊用簡單的 Todo List 來做看看 styled component
- 流程:
總之先想像好版面可能會長怎麼樣,切好 component 之後再一一幫每一個 compontent 加上 CSS 跟功能!
```javascript
// 先想像頁面會長怎樣,需要那些 component
function App() {
return (
<div className="App">
<TodoItemWrapper>
<TodoContent size="XL">I am todo</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<Button>刪除</Button>
</TodoButtonWrapper>
</TodoItemWrapper>
</div>
);
}
大概長相,那我們接下來就要做
<TodoItemWrapper>
<TodoContent>
<TodoButtonWrapper>
<Button>
這幾個 component
```
再將 component 一一的寫上 CSS 跟詳細資料
```javascript
const TodoItemWrapper = styled.div`
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 16px;
border: 1px solid black;
`
const TodoContent = styled.div`
color: #e1bee7;
// 這個寫法是三元運算寫法,意思等價於下面
font-size: ${props => props.size === 'XL' ? '36px' : '20px'}
// 這個寫法意思等價於上面
font-size: 12px;
${props => props.size === 'XL' && `
font-size: 20px;
`}
`
const TodoButtonWrapper = styled.div``
const Button = styled.button`
padding: 4px;
color: black;
&:hover {
color: red;
}
& + & {
margin-left: 5px;
}
`
```
目前長相

### 3. styled component 簡單示範 todo - 3 / 3
最後介紹一下,其實我們應該也要把 todo 給拉出來變成一個 component
```javascript
// 建立好一個獨立的 TodoItem ,再將 component 放進去
function TodoItem({ size, content }) {
return (
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<Button>刪除</Button>
</TodoButtonWrapper>
</TodoItemWrapper>
)
}
// 再引入上面建好的 component ,是不是有超級模組化的感覺呀!
function App() {
return (
<div className="App">
<TodoItem content={'第一則'} />
<TodoItem content={'第二二二則'} size="XL" />
</div>
);
}
```
目前長相

---
styled component 的基本介紹就到這邊,接下來請
**多多練習用 styled component 切版**
還有目前在 CSS 方面,還有 RWD 及 SASS 變數引入的問題,下一章會提到!
### restyle
>設定完的 component 也可以再拿來使用,可以只修改部分的屬性
以下案例多建立一個 `RedButton` 的 component,並且其他的屬性都從原本的 `Button` 那邊拿
```javascript
const Button = styled.button`
padding: 4px;
color: black;
&:hover {
color: red;
}
& + & {
margin-left: 5px;
}
`
const RedButton = styled(Button)`
color: red;
`
function TodoItem({ size, content }) {
return (
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<RedButton>刪除</RedButton>
</TodoButtonWrapper>
</TodoItemWrapper>
)
}
```
這樣 `RedButton` 的 component 就建立好囉,只有顏色改成紅色的

## styled component 實戰
推薦去看完官方文件:
[styled component - Basics](https://styled-components.com/docs/basics#getting-started)
### restyle 再提一次
>上面不是有對 `RedButton` 的 component 做 restyle
這邊要介紹如果是對正常的 component 做 restyle 要怎麼做
```javascript
function TodoItem({ size, content }) {
return (
<TodoItemWrapper>
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<RedButton>刪除</RedButton>
</TodoButtonWrapper>
</TodoItemWrapper>
)
}
// 加了這一段,但其實是沒屁用的
const BlackTodoItom = styled(TodoItem)`
background: black;
`
function App() {
return (
<div className="App">
<TodoItem content={'第一則'} />
<BlackTodoItom content={'第二二二則'} size="XL" />
</div>
);
}
```
這邊沒有作用的原因就是剛剛有提到,styled component 的原理其實是
>動態產生一個 class name,然後幫你把 class name 放在 <你指定的> 這個元件上面,最後幫你產生 CSS
所以要先把 className 要放的地方做好
這樣就可以囉!
```javascript
function TodoItem({ className, size, content }) {
return (
<TodoItemWrapper className={className}> // 這裡要指定好下面那段產生的 class 要放在這裡
<TodoContent size={size}>{content}</TodoContent>
<TodoButtonWrapper>
<Button>已完成</Button>
<RedButton>刪除</RedButton>
</TodoButtonWrapper>
</TodoItemWrapper>
)
}
// 這段會產生一個有 background: black; 屬性的 class
const BlackTodoItom = styled(TodoItem)`
background: black;
`
function App() {
return (
<div className="App">
<TodoItem content={'第一則'} />
<BlackTodoItom content={'第二二二則'} size="XL" />
</div>
);
}
```
這樣就可以囉!

這邊小結:
- 所以我們也可以對一般的 component 做 style component 做的事情,只是我們要多寫一個接收 `className` 的地方。
就像這個啦
```javascript
<TodoItemWrapper className={className}>
```
如果直接對 style component 做 restyle 就可以直接寫。
就像這個啦
```javascript
const RedButton = styled(Button)`
color: red;
`
```
接下來要介紹 media query,就是 RWD 的用法啦!
### RWD 寫法 - media query
最基本但是不會這樣用的寫法:
其實寫在 CSS 裡面就好
```javascript
// 樸實無華的寫在裡面
const Button = styled.button`
padding: 4px;
color: black;
font-size: 20px;
@media screen and (min-width: 768px) {
font-size: 12px;
}
`
```
但是一般不會這樣用,一般用法如下:
1. 會另外建一個放置常數的資料夾存取這些資料,像現在的 RWD 就會叫做 `breakpoint.js`。
2. 再由原本的地方引入進去
```javascript
// constants/breakpoint.js
export const MEDIA_QUERY_MD = '@media screen and (min-width: 768px)'
export const MEDIA_QUERY_LG = '@media screen and (min-width: 1024px)'
```
```javascript
// App.js
import { MEDIA_QUERY_MD, MEDIA_QUERY_LG } from './constants/breakpoint'
const Button = styled.button`
padding: 4px;
color: black;
font-size: 20px;
${MEDIA_QUERY_MD} {
font-size: 12px;
}
${MEDIA_QUERY_LG} {
font-size: 8px;
}
`
```
這樣就可以設定 RWD 囉,乾乾淨淨很好切開。
### 如何向 SASS 一樣使用 CSS 的變數
一樣參照官方文件
[Advanced Usage - 高級用法的意思 - Theming](https://styled-components.com/docs/advanced#theming)
這邊大概提一下目前用到的資料哦(只提用到的,其他先不提)
剛剛都是在 App.js 裡面更改、建立 component,實際上 render 的頁面應該是 index.js ,而剛剛建立的 RWD 用的 constants 也是在這裡
src/index.js
src/App.js
src/constants/breakpoint.js
現在要示範的東西是在 src/index.js 裡面使用像是 SASS 的變數。
```javascript
// index.js
import { ThemeProvider } from 'styled-components' // 先引入 ThemeProvider
// 這邊規定 theme 的規格,這裡以顏色舉例
const theme = {
colors: {
red_300: '#ff1744',
red_400: '#ba6b6c',
red_500: '#ff79ff',
}
}
// 總之要這樣寫
ReactDOM.render(
<ThemeProvider theme={theme}>
<App />,
</ThemeProvider>
,
document.getElementById('root')
);
```
接下來回到 src/App.js
我們以修改 Todo 的內容做為示範,=> <TodoContent>
```javascript
const TodoContent = styled.div`
color: ${props => props.theme.colors.red_500};
font-size: 12px;
${props => props.size === 'XL' && `
font-size: 20px;
`}
`
```
這樣就會成功引入 theme 中的顏色囉


這樣就可以成功用到 theme 之中的變數了!詳細好處可以複習 SASS
- 再優化一下名稱
可以用這種取名比較模組化好管理的名稱。
primary 主色的意思,這樣如果哪天想換心情全部主色都更換的話,就只要改這邊就好
```javascript
const theme = {
colors: {
primary_300: '#ff1744',
primary_400: '#ba6b6c',
primary_500: '#ff79ff',
}
}
```
然後不管是 font-size 還是其他類似的概念都可以這樣子寫,這樣子調整
可以去複習 SASS 會比較清楚這樣做的用意為何!
### 這邊學到了 styled component 三個常用到的小技巧!
1. 怎麼寫 RWD media query?
- 引入引入引入 - 透過拆出來的方式來寫!
2. 怎麼像 SCSS 一樣引入 CSS 用的參數
- theme 的概念
3. 怎麼寫 restyle
4. 其他沒講到的功能要自己看說明書比較好哦!
### 請用上面教的觀念練習切版!
>練習切以前作業的板,todolist 阿、twitch 阿,切版的途中也同時再訓練怎麼切 component,怎麼傳參數等等
請練習,用 styled component 切版
- 可以練習到切 components 怎麼傳參數
- React 的切法
- styled component
- component 多了之後可以獨立成一個檔案
可以多開一個 `TodoItem.js` ,把東西都放裡面,再由 `App.js` import 進來用
```javascript
import TodoItem from './TodoItem'
```
通常 component 都用 export default