--- title: 0320課程React description: 測試項目 robots: noindex, nofollow lang: zh-tw dir: ltr breaks: true tags: notion, react disqus: hackmd --- # 開始 React 之前 ## 環境設定 1. `$ brew install node` 安裝 nodejs (10.x以上) 3. `$ node -v` 確認是否安裝完成以及版本 ## VSCode 設定 ### setting.json > CMD+SHIFT+P > Preferences: Open Settings (JSON) ```json= // 在未支援的語言中啟用emmet "emmet.includeLanguages": { "javascript": "javascriptreact" }, // 存檔後,eslint 自動修正 "editor.codeActionsOnSave": { "source.fixAll.eslint": true } ``` ### 擴充套件 - [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) (必裝) - [JavaScript (ES6) code snippets](https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets) (必裝) - [ES7 React/Redux/GraphQL/React-Native snippets](https://marketplace.visualstudio.com/items?itemName=dsznajder.es7-react-js-snippets) - [Highlight Matching Tag](https://marketplace.visualstudio.com/items?itemName=vincaslt.highlight-matching-tag) - [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense) - [REST Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) - [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree) - [Guides](https://marketplace.visualstudio.com/items?itemName=spywhere.guides) ## ES6 [React 起手式 — JS — ES6篇](https://milkmidi.medium.com/react-%E8%B5%B7%E6%89%8B%E5%BC%8F-js-es6%E7%AF%87-4b8f1a9e07e0) ## 使用 React 的風險 (10:06) * SEO 不夠好,因為使用的是 React 的 Virtual DOM **Google 已經可以解決 Virtual DOM 的 SEO 問題 但還有一項風險 yahoo 和 bing 沒有支援Virtual DOM** > 可用 SSR (Sever side render) 解決 > (在 sever 把 HTML 長好再送到客戶端) 工商: 乃綠茶公司 [佳格數位](https://www.104.com.tw/job/786xv?jobsource=company_job) --- # React ## HTML 寫法 ```htmlembedded= <!-- index.html --> <body> <!-- react 只能放到 div 裡 --> <div id="app"></div> <!-- 用 babel 轉譯 jsx --> <script type="text/babel" src="app.js"></script> </body> ``` ## JS 寫法 ```javascript= // app.js ReactDOM.render( // jsx, html 的進入點 <App />, // 要渲染的 html or component document.getElementById('app') // 渲染在哪個 element 上 ); ``` ## Component 組件 ### Functional Component (新式現正流行中) ```jsx= function FunctionalComponent(){ return( <div className="function-component"> 這是 FuctionComponent 組件 <br/> 今天日期: { new Date().toDateString() } </div> ) } // 你也可以使用箭頭函示 const FunctionalComponent2 = () => { return( <div className="function-component"> 這是 FuctionComponent 組件 <br/> 今天日期: { new Date().toDateString() } </div> ) } ``` ### Class Component (舊式,不支援 hooks) ```jsx= class MyComponent extends React.Component { render() { return ( <div className="react-component"> 這是 React Class Component 組件 <br/> { 9000 + 527 } </div> ); } } ``` ### 為何取名一定要大寫開頭? 物理上 => 如果 function 使用 div 取名 那到底他會認為是 html 的 div?還是 function 的 div? 導致不會執行空白也不會噴錯 ```jsx= function div(){ // ... } ReactDOM.render( <div/> //是html div? 還是 component div? ) ``` ### 為何 return 要使用 `()` 包起來? 為了可讀性以及排版需要斷行如果不使用 `()` 包起來會錯誤 JS 會很貼心的在 return 句尾補上 `;` ```jsx= function Ck(){ return 9527; } // => undfined // 實際上會變成 function Ck(){ return; 9527; } ``` 不使用 `()` 的方式,雖然還是會 return 正確的值但會造成程式上難以閱讀! ```jsx= const Ck = () => { return <div className="function-component"> 這是 FuctionComponent 組件 <br/> 今天日期: { new Date().toDateString() } </div> } ``` ## Props :::warning 1. component 接收參數的唯一方法就是從 `props` 取得 2. functional component 只接收一個參數 props 3. 要使用props 請先解構(const),增加可讀性。 ::: 要使用props 請先解構(const),增加可讀性。 基本上在 component 設定的值都會變成 props 傳進去 `children` 是包裹在 component 裡頭的元素像是以下範例第二個 `FunctionalCard` 裡的 `h1` ==`children` 為 react 的關鍵字 如果有取名的話不能使用!== 以下為 ES6 解構賦值的範例 ```jsx= const { img,name,children } = props; ``` ```jsx= const FunctionalCard = (props) => { const { img,name,children } = props; return( <div className="card"> <img src={img} alt="" className="img"/> <div className="name">name: {name}</div> <div className="quote">quote: {children}</div> </div> ) } ReactDOM.render( <div className="app"> <FunctionalCard img="http://fakeimg.pl/300x100/ecf0f1/" name="milkmidi" /> <FunctionalCard img="http://fakeimg.pl/240x80/ecf0f1/" name="奶綠茶" > <h1>我是子元素</h1> </FunctionalCard> </div>, document.getElementById('app') ); ``` :::info **課堂小考** 這樣寫 age 傳進去 props 會得到字串的 `"18"` Q: 如果我想接收到的是數字型別的 `18` 呢? ```jsx= <FunctionalCard img="http://fakeimg.pl/240x80/ecf0f1/" name="奶綠茶" age="18" > <h1>我是子元素</h1> </FunctionalCard> ``` ::: :::success A: 透過使用 `{}` 來使用 js 運算得到數字型別的 `18` ```jsx= <FunctionalCard img="http://fakeimg.pl/240x80/ecf0f1/" name="奶綠茶" age={18} > <h1>我是子元素</h1> </FunctionalCard> ``` ::: --- # JSX > javascript extension syntax ## 單一父層元素 :::danger 記住 JSX 只能 render 一個 element 所以如果直接寫這樣會錯 ::: ```javascript= // 錯誤寫法 ReactDOM.render( <App /> <h2>ck</h2>, document.getElementById('app') ); ``` ![](https://i.imgur.com/5dFoLA1.png) :::success 必須要使用一個 html 元素包著! ::: ```javascript= // 正確寫法 ReactDOM.render( <div> <App /> // 要渲染的html <h2>ck</h2> </div>, document.getElementById('app') // 渲染在哪個element上 ); ``` ## Closing tag > 自閉標籤 :::danger jsx 檔的 html 語法一定都要有結尾符號否則會出錯 (ex: `<br/>`) ::: ```jsx= // 錯誤寫法 <br> // 正確寫法 <br/> ``` :::success 與 html tag 規則不同 jsx 內所有標籤都可以加上結束符號 ::: ```jsx= <div/> ``` ## JSX embedding > 在 JSX 檔案中插入 JS 語法 ```jsx= // 使用 {} { new Date().toDateString() } ``` --- # 課堂範例 ## a02_componemt ## State 從 Hook 開始 Function Component 可以使用 State 來更新 props的值 ```jsx= function Counter(){ const [count,setCount] = React.useState(0); const atClick = ()=> { setCount(count + 1); } return ( <div className="counter"> <h1>Counter</h1> <div className="count">{count}</div> <button className="btn" onClick={atClick}>+1</button> </div> ) } ReactDOM.render( <Counter/>, document.getElementById('app') ); ``` `const [count,setCount] = React.useState(0);` 這行也是解構賦值第一個值表示==初始值==第二個為更改這個值的==函式== 我們來看以下情況 ```jsx= function Counter(){ let [count,setCount] = React.useState(0); const atClick = ()=> { count += 1 console.log(count) } } ``` 這樣寫你雖然會看到count確實有被更新但畫面卻沒有?那是因為並無觸發到 React 渲染 :::info **react如何更新畫面?** 1. 只要props值被更改就會重新render一次畫面而且會比對沒有被更改的地方不會更動只會更動被更新的區塊 2. 透過setState()來更新也會更新畫面 ::: 使用useState會將更新的值 keep 住 ## a05 以下三種寫法都是一樣的但建議直接使用最下面的寫法最為簡潔,在react如果寫`null` or `undefined` 都不會做事 ```jsx= {isLoggedIn ? <UserGreeting /> : <GuestGreeting />} {isLoggedIn ? <UserGreeting /> : null } {isLoggedIn && <UserGreeting />} ``` 若有需要轉譯過後的js語法可以到這個網站 [babel](http://es6-features.org/#ExpressionBodies) ## useEffect ```jsx= React.useEffect(() => { console.log('componentDidMount') const timeId = setInterval(() => { //component被建立的時候觸發一次 console.log('setTimeout'); }, 1000); return () => { //這個component死亡後執行一次 clearInterval(timeId); console.log('clear up'); } }, []); //有加陣列的話只有建立跟死亡會觸發 ``` 如果沒有加空array的話只要值有更動useEffect都會重新渲染一次