--- 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