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

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