---
# System prepended metadata

title: '[筆記] React'
tags: [REACT]

---

---
tags: REACT
---
# [筆記] React

- vue為雙向綁定資料與畫面，連動
- React單向，改資料更新畫面，更新畫面不會影響到資料
- `useState`, `useEffec` 最重要的兩個東東

## 參考

- [傳奇人物筆記Dan](https://overreacted.io/)
- [必看文章 A Complete Guide to useEffect](https://overreacted.io/a-complete-guide-to-useeffect/)

## JSX
- 經babel編譯
```htmlembedded=
<button type="button">Click Here!</button>
```
```javascript=
// function，props，children
React.createElement("button", {
  type: "button",
}, "Click Here!");
```
```htmlembedded=
<div>
  <button type="button">Click Here!</button>
</div>
```
```javascript=
React.createElement("div", null, React.createElement("button", {
  type: "button"
}, "Click Here!"));
```

## PropTypes
`檢查參數型態`
```javascript=
import PropTypes from 'prop-types'

MyComponent.propTypes = {
    optionalArray: PropTypes.array,
    optionalBool: PropTypes.bool.isRequired,
    optionalFunc: PropTypes.func,
    // An object taking on a particular shape
    optionalObjectWithShape: PropTypes.shape({
        color: PropTypes.string,
        fontSize: PropTypes.number
    }),
}
```
# State操作
## 1. 新增 - 解構
```javascript=
setTodos([
  {
    id,
    content: inputValue,
    isDone: false,
  },
  ...todos,
])
```

## 2. 刪除 - filter

```javascript=
const handleTodoDelete = id => {
    setTodos(
      todos.filter((todo) => todo.id !== id ),
    )
}
```
## 3. 修改 - map
```javascript=
const handleToggleIsDone = id => {
    setTodos(
      todos.map((todo) => {
        if(todo.id === id)
          todo.isDone = !todo.isDone
        return todo
      }),
    )
}
```

### a 的 href 防 javascript
```
<!-- 例 -->
javascript:alert(2)
```

# Hooks
[Hook flow圖](https://raw.githubusercontent.com/donavon/hook-flow/master/hook-flow.png)

[useHooks網站](https://usehooks.com/)

[從 Hooks 開始，讓你的網頁 React 起來](https://ithelp.ithome.com.tw/articles/10216355)

## 重要觀念
1. 只能在component第一層
2. 不能被function或 if-elase等包起來

## useEffect
- render完要做什麼事?(瀏覽器畫完畫面後想做什麼事)
- `array` 作為可選的第二個參數
```javascript=
import { useEffect } from 'react'
useEffect(()=>{
    console.log('執行完畢')
})

// 僅在count更改時才重新執行 effect
useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); 
```
- 傳空陣列，只有第**一次render會執行**
```javascript=
useEffect(() => {
  fetch('https://jsonplaceholder.typicode.com/todos/1')
    .then(res=>{
      console.log(res)
    })
}, []); 
```

- cleanup effect return 上個state值
```javascript=
  useEffect(() => {
    console.log('current ', value)
    let i = value
    if(i <= 10) {
      i++
      setValue(i)
      console.log('setting ', i)
    }
    // cleanup function
    return () => {
      // 上一個value值
      console.log('cleanup', value)
    }
  }, [value])
```

```javascript=
  useEffect(() => {
    WebSocket.CONNECTING(userID).subscribe(() => {
      // ...
    })
      
    // cleanup function
    return () => {
      // 清掉上一個userID
      WebSocket.disconnect(userID)
    }
  }, [userID])
```

## useLayoutEffect
- render完，瀏覽器 `paint` 前執行

# Hook Flow (Life Cycle)
[Hook flow圖](https://raw.githubusercontent.com/donavon/hook-flow/master/hook-flow.png)
## Mount
### lazy initialized
- 只執行一次
- useState給初始值（這邊只執行一次

## Update
- render
- update dom
- cleanup LayoutEffects
- Run LayoutEffects
- 瀏覽器paints畫面
- cleanup Effects
- Run Effects

## Unmount
- cleanup LayoutEffects
- cleanup Effects

# Memo: 避免不必要的re-render

```javascript=
import { memo } from 'react'

const Button = ({ onClick, children }) => {
  console.log('rerender button')
  return (
    <button
      onClick={onClick}
    >
      {children}
    </button>
  )
}

const MemoButton = memo(Button)
```
- input值變動時，MemoButton不會re-render
```jsx=
<input
    type="text"
    placeholder='enter something...'
    value={value}
    onChange={handleChange}
    />
<MemoButton
    onClick={handleClick}
>
    do button
</MemoButton>
```

## useCallback

- 以下範例，input 與 button無關時，input值有變動，button不要re-render

```jsx=
import useButton from '@/hooks/useButton'

const Button = ({ onClick, children }) => {
  console.log('rerender button')
  return (
    <button
      onClick={onClick}
    >
      {children}
    </button>
  )
}

const MemoButton = memo(Button)

function App() {
  const { value, handleChange } = useInput()
  const { textValue, handleClick } = useButton()

  return (
    <div className="App">
      <input
        type="text"
        placeholder='enter something...'
        value={value}
        onChange={handleChange}
      />
      <div>{value}</div>
      <hr />
      <MemoButton
        onClick={handleClick}
      >
        do button
      </MemoButton>
      <div>Button text: {textValue}</div>
    </div>
  )
}
```

```jsx=
import { useState, useCallback } from 'react'
export default function useButton() {
  const [textValue, setTextValue] = useState('')
  const handleClick = useCallback(() => {
    setTextValue('kerker' + textValue)
  }, [textValue, setTextValue])
  return {
    textValue,
    handleClick,
  }
}
```

### 避免re-render: useMemo

```jsx=
  const s = useMemo(() => {
    return value ? greenStyle : redStyle
  }, [value])
```