---
# System prepended metadata

title: '[week 21] - 1：React (創建環境、CSS 跟 component、styled component)'
tags: [上課筆記 - 二十一周到結束]

---

---
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 元件、組件

在網頁開發的角度，就很像在切版

![](https://i.imgur.com/6WAgi8k.png)

如果依照 Todo 來看
就會有 title 的 Component
新增的 Component
顯示的 Component

每個 Component 代表它是自成其中一個功能的區塊
底下也可以分成小的 Component

![](https://i.imgur.com/8AZXtyn.png)
可以切很細、也可以切很粗，但重點是要考慮到 Component 的重用性！

像是 bootstripts 就把 Component 切到像是 button alert 之類的小組件，因為它可以重用，所以它是個 Component



其實在寫 HTML 也算是一個 Component 



## 資料 vs 畫面

前幾章可以試著跟著做做看！

在做任何改變的時候同時改資料及畫面

![](https://i.imgur.com/O0R3tnl.png)

這樣個方式有一種壞處，如果同時改的時候有哪邊沒改到，可能會資料畫面不一致

解決方法兩種 =>

1. 畫面歸畫面，需要資料的時候在即時的去拿出現在資料

2. 新增修改時只更改資料，畫面都是依據資料 render 出來的

![](https://i.imgur.com/IbZ0TMa.png)

這個就是 React 第二個最重要的觀念

畫面永遠都由 state 產生！

![](https://i.imgur.com/GapRPQc.png)

## **畫面永遠都由 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

![](https://i.imgur.com/esVMRiK.png)

跑起來囉～

---

看專案的第一件事
看 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 ！


用法如下
![](https://i.imgur.com/IBaSbYY.png)
這種寫法也會用到我們熟悉的 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！(請先學方法就好，原理丟掉)

![](https://i.imgur.com/pSGlMUk.png)

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

![](https://i.imgur.com/tbQZXA1.png)

 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 的功能也有做出來
![](https://i.imgur.com/02yQgh6.png)


就是把它當成是一個 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;
  }
`
```

目前長相

![](https://i.imgur.com/pCeI6Yq.png)


### 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>
  );
}
```

目前長相

![](https://i.imgur.com/wC3dzGf.png)

---

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 就建立好囉，只有顏色改成紅色的

![](https://i.imgur.com/1dLkns4.png)






## 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>
  );
}
```

這樣就可以囉！

![](https://i.imgur.com/l0yZ0zz.png)

這邊小結：

- 所以我們也可以對一般的 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 中的顏色囉
![](https://i.imgur.com/134ulf6.png)

![](https://i.imgur.com/SvHnhs1.png)

這樣就可以成功用到 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


