---
# System prepended metadata

title: 20220725 React
tags: [React, JavaScript]

---

# 20220725 React
###### tags: `JavaScript` `React`
![](https://cdn.dribbble.com/users/2442115/screenshots/8699490/media/48bbda278683c7879bebd57f0e2f9271.gif)

- 相比vue門檻高
- 全球最多人使用的框架
- 所有Dom元素用JS產生

* 優勢
	* 全球職缺多
	* stackoverflow討論度高
	* 知名企業使用: fb, ig, netflix, 蝦皮.....
	* <mark>**學會React年薪百萬!!**</mark>

:::danger
<mark>**React 好棒棒！**</mark>
:::


* [上課使用教材](https://docs.google.com/document/d/1ogpmXyQkFYPvnTK-xLK4Fww8hYOkErgzr8A1UHzf5A8/edit#)

## 創建專案
$ npx create-react-app my-app
$ cd my-app
$ npm start


## 裝回套件
裝回使用套件，會產生node modules (node modules不要進版控)
$ npm i
$ npm install

## import 函式
- import
```javascript
import { add, sub } from './utils';

import defaultValue from './utils';

//同路徑，上面兩行合併，才是優雅
import defaultValue, { add, sub } from './utils';
```
---
## React的Dom元素都由js產生
React元件-依功能拆分成不同component
React的Dom-virtual Dom (虛擬Dom)

## JSX: ㄗㄟ ㄟㄙ ㄟㄎ厶
* JS裡面出現類似html的語法
* 建議有使用到可以把副檔名都取jsx

## Render 
要使用多個標籤需用div包住
```javascript
const root = ReactDOM.createRoot(document.getElementById('root'));

root.render(
  <div>
    <h1>H1</h1>
    <h2>H2</h2>
  </div>,
);
```

#### 手繪風繪圖網站
https://excalidraw.com/

### Example2 Component

#### JSX裡面執行JS運算 
[官網說明](https://reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx)
* `{JS Expression}` 包起來
 ex:{3+4} //{7}

* React component 命名：大寫(駝峰)
```
<Item /> //而非<item />
```

> 浮點數加法溢位

### Example3 Props

* component接收參數從props取得
* 從 prop 傳入的東西預設都是 string 型態
* 傳遞非字串(如數字)需要用 `{100}` 包起來

```javascript
ReactDOM.render(
  <div className="app">
    <FunctionalCard 
      img="http://fakeimg.pl/300x100/ecf0f1/" 
      name="aa" />
    // 如果沒有子元素可以自己結束掉
    
    <FunctionalCard 
      img="http://fakeimg.pl/240x80/ecf0f1/" 
      name="aa">
      <h1>children</h1>
    </FunctionalCard>
    // 如果有子元素就要包起來
  </div>
```


> 傳值 VS 傳址(記憶體位置)
> 物件 => 傳址
> number、string 、boolean => 傳值


### Example4 useState
宣告component內的私有變數 useState=> return array

```javascript
  const [count, setCount] = React.useState(0);
// 需透過setCount來改變函式
// useState(0) 設定初始值為零

```


### Example5 ConditionalRendering

* `{isLoggedIn ? <UserGreeting /> : <GuestGreeting />}`
*  一個 jsx <mark>最好</mark>只有一個 Component

### Example6 styleClassBind

* innerCSS 使用object <mark>不建議使用(ex1)</mark>
```javascript=
style={{
          width: 200,
          height: 200,
          backgroundColor: isGreen ? 'green' : 'red',
        }}
```
* 應該新增預寫好的class name
```javascript=
if (isGreen) {
    boxClassName += ' style-green';
  }
```
### Example7 ListRending


* 迴圈產生的 jsx 元素需要有唯一的 key 值

更新資料
* react 會用 object.is()判斷新值與舊值是否相等
	* 用push沒辦法產生新記憶體空間，會被判斷相等，沒辦法更新
	* <mark>想辦法產生新記憶體空間位置 => concat()</mark>



### Example8 useEffect

#### ex1
* 用useEffect設定component 的出生與死亡
```javascript
React.useEffect(() => {
  console.log('mounted');
  // ...
  return () => {
    console.log('unmount');
    // ...
  }
},[])
```

#### ex3
* 用useEffect 關注值的變化
	* 填關注的變數在[]內
	[]  <---這叫dependency array，陣列內的值(放要監聽的值)，如果沒放（[]空陣列）代表的只有React的週期（建立＆死亡），一旦有變動，整個effect(()=>{})都會再執行一次



### Example10 fetch_api

* useEffect & useEffect 內的function 皆是非同步

```javascript
React.useEffect(() => {
import { useEffect, useState } from 'react';

const FetchAPIExample = () => {
  const [data, setData] = useState([]);
  console.log(data);
  // 第一次會是空陣列, 接著才會獲得值
  // 空陣列 -> 到data.map（沒有項目的狀態）-> useEffect (更新setData 觸發react更新) -> 丟資料 ->react更新 -> data就會有資料 -> 畫面更新
  // TODO
  // useEffect & useEffect 內的function 皆是非同步 會在web api等待
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/todos')
      .then((res) => res.json())
      .then((data) => {
        setData(data); // setData使元件狀態更改，進而re-render
      });
  }, []); // [] -> React的建立跟死亡
  return (
    <section data-name="Example10">
      {data.map((item) => {
        return (
          <div key={item.id} className="border">
            <p>{item.title}</p>
            <small>{item.id}</small>
          </div>
        );
      })}
    </section>
  );
};

export default FetchAPIExample;

```



### Example12 Form

* 透過元素上的 onChange 監聽表單元素異動，更新 Component 的變數



```javascript
import React, { useEffect } from 'react';

// FIXME 實作 email 即時驗證

function validateEmail(email) {
  const re =
    /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  return re.test(String(email).toLowerCase());
}

//
const FormInput = () => {
  const [name, setName] = React.useState('');
  const [isVaild, setIsVaild] = React.useState(false); // 塞初始值-> false
  const atChange = (e) => {
    // 類似 vue 的雙向綁定 v-model
    // TODO
    setName(e.target.value); // 監聽到內容改變時，設定給變數 name 
  };

  React.useEffect(() => {
    const isValideEmail = validateEmail(name); // 2.檢查新的 name 是否合法
    setIsVaild(isValideEmail); // 3.儲存檢查結果，並視需要自動重新 render 畫面 
  }, [name]); // 1.觀察 name 有無改變，name 一改變就執行上兩行

  return (
    <section data-name="FormInput">
      <p>name:{name}</p>
      {/* TODO */}
      <input
        type="text"
        className="my-input"
        value={name}
        onChange={atChange}
      />
      {isVaild ? 'ok' : 'error'}
    </section>
  );
};

export default FormInput;

```

### Example17 ComponentCommunication

* component（一等親傳遞）的傳遞靠props 