---
# System prepended metadata

title: React Hook - useState
tags: ['Javascript, React']

---

#  React Hook - useState

###### tags: `Javascript, React`


## Few gotchas need your attention

##  1. 在 class component 內不能操作

基本上 class component 有類似的功能可以操作

```javascript=
App extends React.Component {
    // 不能在內使用 useState 等 hook 
}
```

只能操作在 function component 內

```javascript=
function App() =>{
    // 可以使用 useState 等 hook
}
```

## 2. 不用針對 hook 使用判斷

基本上不能對 hook 使用 if/else , switch 等等判斷式會影響其順序

```javascript=
if(true){
    useState();
  }
```
IDE 以及瀏覽器都會報錯
![](https://i.imgur.com/DV0yjkL.png)


這樣就沒有問題，因為 hook 們可以照順序執行
```javascript=
function App() =>{
    useState();
    useState();
    useState();
    useState();
}
```

## useState 簡介

1. 會解構出當前的 state 以及一個可以更新 state 的方法
2. 右邊 useState 內的值為 state 初始值

```javascript=
function App() {

  const [count, setCount] = useState(4)

  return (
    <div className="App">
      <button>-</button>
      <span>{count}</span>
      <button>+</button>
    </div>
  );
}
```
印出結果就會把初始值印出來瞜

![](https://i.imgur.com/vclgngG.png)

## preState 介紹

這邊會是正常的讓加減符號正常運作，運用到 preState 帶入目前的 state 值做運算

```javascript=
function App() {

  const [count, setCount] = useState(4)

  function decrementCount(){
    setCount(preCount => preCount -1);
  }
  function incrementCount(){
    setCount(preCount => preCount +1);
  }

  return (
    <div className="App">
      <button onClick={decrementCount}>-</button>
      <span>{count}</span>
      <button onClick={incrementCount}>+</button>
    </div>
  );
}
```

但是如果情況是這樣會讓點擊減號時數字會因為觸發兩次而減二，會追蹤現況作者比較推薦這樣寫


```javascript=
function decrementCount(){
    setCount(preCount => preCount -1);
    setCount(preCount => preCount -1);
  }
```


但是如果我們使用了，卻只會減一而已，因為第二次的 setCount 內部的 count 還未更新，所以依舊是初始值所以只是取代掉了前面的而已，因此不推薦這樣寫

```javascript=
function decrementCount(){
    setCount(count -1);
    setCount(count -1);
  }
```

## 當初始值很複雜很吃效能時，可以這樣處理

運用下方的寫法就可以讓初始值就只會跑一次，就不會每次更新 state 就再跑一次浪費效能

```javascript=
  const [count, setCount] = useState(() =>{
      // put your code here 
      console.log('function run')
      return 4
  })

```
點擊更新 state 時，都不會再次觸發（這邊我點到八都沒觸發）
![](https://i.imgur.com/BwPPfBo.png)


### 對照組

這邊就是每次都會觸發函式的對照

```javascript=
function countInitial(){
console.log('function run')
return 4
}

function App() {

  // 這樣就會在每次點擊按鈕加減時觸發 re-render 並且每次都會觸發這個函式
  const [count, setCount] = useState(countInitial())
}
```
他每次都會更跑一次初始值的函式浪費效能
![](https://i.imgur.com/7vfyros.jpg)

## 面對物件時 FC 的操作

假設情況我們想要在我們要操作的的數字旁邊加一個主題

```javascript=
function App() {

  const [state, setState] = useState({count:4, theme:'Blue'})
  const count = state.count;
  const theme = state.theme;

  function decrementCount(){
      setState(prevState =>{
      return {count: prevState.count - 1}
    })
  };
  function incrementCount(){
    setCount(preCount => preCount +1);
  }

  return (
    <div className="App">
      <button onClick={decrementCount}>-</button>
      <span>{count}</span>
      <button onClick={incrementCount}>+</button>
    </div>
  );
}
```


理想的狀況是我在按下減號之後會出現 3Blue 
![](https://i.imgur.com/UTPFKbc.png)

但卻變成這樣
![](https://i.imgur.com/Ptn1rde.png)

從範例可以看出物件的部分它並沒有把更新後的 count state merge 進去原本的物件，而是直接取代原本的 state，所以這邊 theme 直接被取代消失了

所以如果你還是想要使用原本的物件內容的話必須這樣操作：

用展開運算子複製原本的 state 並且在後面更新 count 的內容就可以保留物件完整內容摟
```javascript=
function decrementCount(){
      setState(prevState =>{
      return {...prevState, count: prevState.count - 1}
    })
  };
```

然而，比較推薦的寫法會是使用多個 state hook 來取代這種物件的寫法會更方便管理

```javascript=
const [count, setCount] = useState()
const [theme, setTheme] = useState()
```