---
# System prepended metadata

title: JS React(09/10) 五倍紅寶石(第八屆共筆)(2021/8/24)
tags: [JavaScript, React]

---

# JS React(09/10) 五倍紅寶石(第八屆共筆)(2021/8/24)
## 講師簡介及建議
奶綠茶，目前任職於 Positive Grid
先找一份工作再說，工作兩三年後再看對前後端哪個有興趣
很少有人能做到全端，建議挑一個
解決問題、溝通表達、會寫文件的能力很重要!

### cdn.js
open source 套件包，有很多好用的套件
可以不用輸入終端機指令，直接安裝套件
全球有部署很多主機，會自動判斷你的位置在哪，再幫你找離你比較近的主機位置
[cdnjs](https://cdnjs.com/)

### CSS
寫兩個 id，有的瀏覽器後者寫的會蓋掉前者

## React 簡介
有大佬在背後撐著(Facebook)
只負責 MVC 的 View 部份，因此不算框架，彈性高
React 只提供大框架，裡面還是要自己寫JS
Vue 則是有他自己的語法，類似 Rails 黑魔法的概念，要再額外花心力去記語法

- 優點
  只要專注在 data-binding 就好也就是專注在資料上
  剩下的東西 React 會幫你 render 出來
  完全由 JS 操作 UI，使得它可以跟後端分離，達到即時互動、自動更新的效果

- 原生 DOM:
  元素實際存在於網頁中，網頁檢查原始碼可看的到
  早期 google 搜尋引擎只會爬靜態資料，但現在改了，也會支援 Virtual DOM 的 SEO
  yahoo、bin瀏覽器目前還是不支援

- Virtual DOM
  所有元素都是用 React 動態長出的，是虛擬元素，網頁檢查原始碼看不到

React 可以做到前後端分離，前後端只要互相知道規格就可以用 api 溝通
但用傳統的 JS 很難 co-work

### JSX
在 JS 裡面寫類似 HTML 的語法，長得很像 HTML 但卻是 JS，可以在 view 產生 HTML

### 實作
- babel.js:
因為 JSX 語法瀏覽器不認識，所以交由 babel 幫你即時編譯 JSX 內容成 JS，讓瀏覽器看得懂，
但 cdn 的 babel 效能很低，不要在網站上使用，可以用終端機指令安裝在本地端
參考:
[搞懂為何設定 REACT、JSX、ES2015、BABEL、WEBPACK 的學習筆記](https://blog.turn.tw/?p=3532)
[[ES6-重點紀錄] 開發環境建置(上) - Babel 編譯工具](https://ithelp.ithome.com.tw/articles/10197028)

01_helloworld
```js
// ReactDOM 裡面有 render 方法，第一個參數是 JSX，告訴 HTML 我要render h1 這個 JSX 動態元素，記得後面要加逗號！第二個參數是我要長在哪裡
// 一個 ReactDOM.render 只能有一個根節點，如果放超過一個會出錯：Adjacent JSX elements must be wrapped in an enclosing tag
// 解決方法：用 div 把他包起來就只有一個根節點
ReactDOM.render(
  <div>
    <h1>123</h1>
    <h2>123</h2>
  </div>,
  document.getElementById('app')
);
```
02_component
```js
// 早期寫法，現在不要這樣寫了
class MyComponent extends React.Component {
  render() {
    return (
      <div className="my-component">
        這是ReactComponent組件
      </div>
    );
  }
}

// 現代寫法
// FunctionalComponent 就是 JS 的 function 
// component 名稱一定要用大寫開頭，才能透過 JSX 去編譯，同時也可以跟 HTML 標籤做區分
// return JSX 元素
// class 要寫成 className，跟原本的 CSS 做區分
// JSX 內用{}包起來代表的是 JS 的運算
// 沒包的就是 JSX 語法
// return 的()是為了防止 JS 自動幫你加 ; 導致 return undefined
function FunctionalComponent() {
  return (
    <div className="functional-component">
      <br/>
      {
        new Date().toDateString()
      }
    </div>
  )
}

// 所有的元件(component)跟 JSX 元素都要有結束標示 "/"
ReactDOM.render(
  <div>
    <MyComponent />
    <FunctionalComponent />
  </div>
  ,
  document.getElementById("app")
)
```
03_props
```js
// 初學者用 component 接收參數的唯一方法就是透過 props 取得，不要打破這個原則
// 進階版的先不用學
// props 是 object
// const {img, name, children} = props 是用解構賦值方式取出 key (img,name,children)
// children 是特有的 key，內建的關鍵字
// 所有要透過 JS 運算的東西都是用 {} 包起來 ex:{img} {name} {children}
// name: 只是字串，因為是包在<div></div>裡面，跟一般 HTML 標籤用法一樣

function FunctionalCard(props){

  const {
    img, name, children
  } = props;
  return (
    <div className="card">
      <img className="img" src={img}/>
      <div className="name">name:{name}</div>
      <div className="quote">quote:{children}</div>
    </div>
  );
}
  
// 客製化的 component
// 把 參數(img="http://fakeimg.pl/300x100/ecf0f1/" name="milkmidi")丟到 component 裡
// 如果參數裡面有 JSX(這邊的<h1>標籤)，回傳時會把他丟到props 裡的 children，用 children 來接收
// 如果在這邊直接用內建關鍵字 children 當屬性名稱傳入 prop ，React 預設還是會傳入(這邊的<h1>標籤)
// props 傳的參數一律都是字串，如果要傳其他型態的值的話要用{}包起來，React 會自動幫你判斷他的原始資料型別

ReactDOM.render(
  // TODO2
  <div className="app">
    <FunctionalCard
      img="http://fakeimg.pl/300x100/ecf0f1/"
      count={1}
      bool={true}
      name="milkmidi" />
    <FunctionalCard
      img="http://fakeimg.pl/240x80/ecf0f1/"
      name="奶綠茶">
      <h1>我是子元素</h1>
    </FunctionalCard>
  </div>
  //
  ,
  document.getElementById('app')
);
```
04_setState
```js
// 這邊的 useState 是 hooks 用法，專案一定會用到
// 原本是宣告私有變數0 回傳給 array 
// [count, setCount] 是 array 的解構賦值
// const [count, setCount] 的第二個參數專門用來更改第一個參數，呼叫 setCount 時，count 就加1
// setCount 被觸發時瀏覽器會重新 render，並且使用 React 提供得 useState 瀏覽器才會知道要更新頁面
// onClick = addeventlisten(click)

function Counter(props){
  const {
    // 加預設值防呆，怕使用者輸入沒有輸入值會變成undefined，造成結果是NAN
    initCount = 0
  } = props;
  const [count, setCount] = React.useState(initCount);
  const atClick = () => {
    setCount(count + 1);
  }
  return (
    <div className="counter">
      <h1>Counter</h1>
      <div className="count">{count}</div>
      <button className="my-btn" onClick={atClick}>+1</button>
    </div>
  );
}
// 加{}讓字串變數字
ReactDOM.render(
  <div>
    <Counter initCount = {0}/>
    <Counter initCount = {1}/>
  </div>
  ,
  document.getElementById('app')
);
```
05_Conditional-Rendering
```js
// 透過 true false(選擇性切換) 來切換要 render 登入成功 還是 Please sign up.
// 三元運算子在 React 很常用
// React 不是用 display none/block 切換 CSS，而是直接刪掉再重新render，所以效能會差一點點

function App(){
  const [isLoggedIn, setLoggedIn] = React.useState(false);
  const atClick = () => {
    setLoggedIn(!isLoggedIn);
  }
  return (
    <div className="app">
      <button onClick={atClick} >{isLoggedIn ? "登出" : "登入"} </button>
      {isLoggedIn ? <UserGreeting name="milkmidi" /> : <GuestGreeting /> }
      {isLoggedIn && <UserGreeting name="milkmidi" />}
    </div>
  )
}
```
06_style-class-bind
```js
// 用某個變數控制 class 名稱
// 第二個參數用來更改第一個參數，所以每次點擊按鈕都會觸發 setGreen 改變 isGreen 狀態
// style={{}} 的第一個{}是 JSX 第二個{}是物件
// <div className={boxClassName} /> 因為沒有要在div裡面塞東西所以直接截斷，看起來比較簡短

function App(){
  const [isGreen, setGreen] = React.useState(false);
  const atClick = () => {
    setGreen(!isGreen);
  }
  var boxClassName = 'box';
  if (isGreen) {
    boxClassName += ' style-green';
  }
  return (
    <div className="app">
      <button className="my-btn" onClick={atClick}>isGreen</button>
      <div className={boxClassName} />
      <div style={{
        width: 200,
        height: 200,
        backgroundColor: isGreen ? 'green' : 'red',
        display: isGreen ? 'block': 'none'
      }} />
    </div>
  )
}
```
07_useEffect
app.js
```js
// 用 show 控制 <Clock /> 的出現及消失
// 用來觸發 Clock.js 的 useEffect
function App(){
  const [show, setShow] = React.useState(false);
  const atClick = () => {
    setShow(!show);
  }
}
```
Clock.js
```js
// useEffect 知道component的建立與死亡，建立跟死亡都只會發生一次
// 常用在api上，被建立就打api到後端
// React 的 生命周期方法:componentDidMount、componentWillUnmount，是固定用法，可參考官網
function Clock() {
  React.useEffect(() => {
    // 建立時發生，執行componentDidMount ex: setinterval
    console.log('componentDidMount')
    return () => {
    // 死亡時發生，執行componentWillUnmount ex: clearinterval
      console.log('componentWillUnmount');
    }
  }, []);
}
```
08_list-rendering
```js
// 點擊後新增資料進去
// 使用原生 JS return JSX 元素出來時，用迴圈產生的 vitual dom 會遺失 key，所以要手動幫他寫一個 key 值
// Key 幫助 React 分辨哪些項目被改變、增加或刪除。在 array 裡面的每個 element 都應該要有一個 key，如此才能給予每個 element 一個固定的身份
// https://zh-hant.reactjs.org/docs/lists-and-keys.html
// className 加 data 屬性就可以在瀏覽器看到
// 不然一般寫的 JSX 在瀏覽器看不到
// 傳值跟傳址(傳記憶體位址)
// === 型別跟記憶體位置都一樣才會是true
// react 不會 render 型別跟記憶體位置都一樣的變數
// 所以要使用 concat 讓原本的 array 的值一樣但產生新的記憶體位置
// 這樣才能 render 出來 
// 當初 react 設計理念就是這樣，因為背後是用 === 去做判斷
// 不希望你去動到裡面的東西

function List(){
  const [list, setList] = React.useState(['學會 JS', '學會 React', '年薪百萬']);
  const atAddClick = () => {
    var newList = list.concat(new Date().toString());
    setList(newList);
  }
  return (
    <div>
      <button onClick={atAddClick}>Add</button>
      <ol className="list">
      {
        list.map(function (text) {
          return <li key={text}>{text}</li>;
        })
      }
      </ol>
    </div>
  )
}
```
09_list-rendering-advance
```js
// 打 api，接api
// 用 useEffect 的時候可以打
// 是實際上會用到的開發技巧！
function List(){
  const [list, setList] = React.useState([]);
  React.useEffect(() => {
    fetch("./categories.json")
      .then((res) => res.json())
      .then((categories) => {
        console.log(categories)
        setList(categories)
      })
  }, [])
  
  return (
    <div>
      <div className="category-wrap">
      {
        list.map((category) => {
          return (
            <CategoryItem
              key={category.id}
              name={category.name}
              image={category.image} />
          )
        })
      }
      </div>
    </div>
  )
}
```
### 補充
- 數位邏輯
  10 >> 1 = 5

- 把網頁包進應用程式
  VScode & Spotify 本身是網頁，用打包工具把網頁塞進去變應用程式
  可以在說明那邊開開發者工具檢視原始碼檢查

- 浮點數
  瀏覽器物件距離的最小單位是1px
  有的瀏覽器(ie)用浮點數畫面會變得怪怪的，可能會超自然抖動

- setinterval
  使用 setinterval 會造成 memory leak
  搭配 useState 使用時要用 clearinterval 清掉才不會記憶體越疊越高造成 stack overflow

- vscode extensions
https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer
https://marketplace.visualstudio.com/items?itemName=xabikos.JavaScriptSnippets
https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree
https://marketplace.visualstudio.com/items?itemName=formulahendry.auto-rename-tag
settings.json 設定:
"emmet.includeLanguages": {
  "javascript": "javascriptreact"
}

- JS Vue推薦書
  Kuro 老師的[0 陷阱！0 誤解！8 天重新認識 JavaScript！（iT邦幫忙鐵人賽系列書）](https://www.tenlong.com.tw/products/9789864344130)[重新認識Vue.js：008天](https://www.books.com.tw/products/0010883365)

- 課後練習
  1. 自己做出一個todo-list
  2. 想想看專案哪一部分可以用 React 寫，為什麼要用?

---

###### tags: `JavaScript` `React`