iT邦幫忙

2026 iThome 鐵人賽

DAY 16
0
JavaScript

JavaScript為什麼筆記本系列 第 16

Day 16|登入狀態為什麼不能只寫成 `const`?先把 `useState` 這一行看懂

  • 分享至 

  • xImage
  •  

今天要弄懂:

const [user, setUser] = useState(null)

這一行在幹嘛?

我們先從會員登入這件事情開始。


會員系統其實只是在問:現在有沒有人登入?

假設一開始還沒登入。

我們可以先用:

null

表示「目前沒有會員」。

所以:

useState(null)

裡面的 null,今天先理解成:

會員登入狀態一開始是空的,也就是還沒有人登入。

如果 Anthony 登入成功,之後我們希望 user 變成:

{
  name: 'Anthony'
}

所以整件事情其實就是:

一開始
null

↓ 登入成功

後來
{ name: 'Anthony' }

我們現在需要一個地方,把「目前是哪一個狀態」記住。

這就是 useState 在這裡要幫我們做的事情。


先只看右邊:useState(null)

先把左邊全部遮住:

useState(null)

這裡其實有兩件不同的東西:

useState
→ React 提供的 Hook
→ 「state」的概念是從這裡進來的

null
→ 傳給 useState 的初始值
→ 表示一開始還沒有會員登入

所以:

useState(null)

不是「null 就是 state」。

比較準確的讀法是:

React,我要用 useState 管理一份 state;這份 state 一開始的值是 null

換句話說:

state 是什麼?
→ React 幫 Component 記住、而且更新後會影響畫面的資料

那 null 是什麼?
→ 這份 state 的初始值

會員登入狀態就很符合。

因為它可能從:

未登入

變成:

已登入

而畫面也會跟著不同。

例如:

未登入
→ 顯示 Sign In

已登入
→ 顯示 Hello, Anthony

那左邊的 [user, setUser] 是什麼?

再看完整一點:

const [user, setUser] = useState(null)

呼叫 useState(null) 之後,React 會回傳兩個東西。

可以先想成:

第一個
→ 目前這份 state 的值

第二個
→ 更新這份 state 的 function

放到會員系統就是:

user
→ 目前的 state 值
→ 現在登入的是誰

setUser
→ 更新這份 state 的 function
→ 之後要修改登入狀態時使用

所以這一整行可以拆成:

const [user, setUser] = useState(null)

useState
→ 告訴 React:我要管理一份 state

null
→ 這份 state 的初始值

user
→ 目前拿到的 state 值

setUser
→ 更新這份 state 的 function

所以:

const [user, setUser] = useState(null)

現在可以先翻成中文:

React,請幫我記住會員登入狀態。
一開始沒有人登入,所以是 null。
現在的登入資料叫 user。
以後要改它,就用 setUser。

這樣就已經比整句硬背容易很多了。


為什麼外面有一個 []

這個 [] 不是 React 特殊語法。

它是 JavaScript 的 Array 解構

useState(null) 可以先想成 React 回傳兩個東西:

[
  目前的值,
  修改它的 function
]

usersetUser 是 React 規定的名字嗎?

不是。

我們自己取的。

例如可以寫:

const [member, changeMember] = useState(null)

只是 React 很常用這種命名方式:

user
setUser

count
setCount

isOpen
setIsOpen

所以看到:

const [user, setUser] = useState(null)

可以先找規律:

資料:user
修改資料:setUser

那登入成功之後,要怎麼把 Anthony 放進去?

一開始:

const [user, setUser] = useState(null)

所以:

user
→ null

假設登入成功後,我拿到:

{
  name: 'Anthony'
}

這時候可以:

setUser({
  name: 'Anthony'
})

先不要想太多。

今天只需要知道:

setUser(...)
↓
把 user 更新成新的會員資料

於是概念上就變成:

原本

user = null

↓ setUser({ name: 'Anthony' })

後來

user = { name: 'Anthony' }

這就是會員系統裡 useState 最實際的用途。


可是為什麼不能直接寫 const user = null

如果寫:

const user = null

它當然可以代表「目前沒登入」。

但登入之後,我們不能再做:

user = {
  name: 'Anthony'
}

因為 const 不能重新賦值。

那換成 let 呢?

let user = null

JavaScript 的確允許:

user = {
  name: 'Anthony'
}

可是這裡又出現 React 的需求。

我們不只想把資料改掉。

我們還希望:

user 改了
↓
畫面也重新看一次 user
↓
決定現在要顯示什麼

所以 React 才不是只叫我們放一個普通的 let user

而是:

const [user, setUser] = useState(null)

setUser 更新時,React 會知道:

這個資料改了,畫面可能也要更新。

先理解到這裡就夠了。


明明 user 會變,為什麼這裡還是 const

這一行看起來很奇怪:

const [user, setUser] = useState(null)

剛剛明明才說 user 之後會變。

為什麼還是 const

因為我們不是這樣改:

user = {
  name: 'Anthony'
}

而是:

setUser({
  name: 'Anthony'
})

也就是說:

我們沒有直接重新指定這一次的 user,而是請 React 更新它記住的會員狀態。

所以這裡可以繼續用 const


現在先只看這段:

import { useState } from 'react'

function App() {
  const [user, setUser] = useState(null)

  function login() {
    setUser({
      name: 'Anthony'
    })
  }

  return (
    <div>
      <p>
        {user ? `Hello, ${user.name}` : '尚未登入'}
      </p>

      <button onClick={login}>
        Sign In
      </button>
    </div>
  )
}

先拆成兩部分。

第一部分:

const [user, setUser] = useState(null)

負責:

記住目前登入狀態

第二部分:

{user ? `Hello, ${user.name}` : '尚未登入'}

負責:

看 user 現在有沒有資料
↓
決定畫面顯示什麼

所以如果:

user = null

畫面就是:

尚未登入

如果 user 之後變成:

{
  name: 'Anthony'
}

畫面就可以變成:

Hello, Anthony

onClick 部分

現在才輪到按鈕。

我們希望:

按下 Sign In
↓
setUser(...)
↓
user 變成 Anthony

可以先寫成:

<button
  onClick={() => {
    setUser({
      name: 'Anthony'
    })
  }}
>
  Sign In
</button>

今天先不要研究:

() => {}

也不要研究 event。

只把:

onClick={...}

理解成:

使用者按下按鈕時,再執行裡面的程式。

所以整個流程就是:

一開始

user = null
畫面:尚未登入

↓ 按 Sign In

setUser({
  name: 'Anthony'
})

↓

user 變成 Anthony
畫面:Hello, Anthony

這就是今天真正想看到的結果。


原來「render」只是這件事的名字

前面沒有先講 render。

因為如果一開始就看到:

state 更新
→ re-render
→ state preservation

我其實還是不知道畫面到底發生什麼事。

現在用會員登入看,就比較有畫面了。

React 原本用:

user = null

算出:

尚未登入

按下 Sign In 後,user 更新。

React 再用新的:

user = { name: 'Anthony' }

重新算一次現在應該顯示什麼。

變成:

Hello, Anthony

render:React 執行 Component、計算這次畫面應該長什麼樣子。

所以目前可以先記成:

render
≈ React 根據現在的資料,算一次畫面要長怎樣

那 state preservation 又是什麼?

這個詞聽起來很可怕。

但現在其實也可以用會員登入理解。

按下 Sign In 之後:

user = Anthony

React 為了更新畫面,會再執行一次 Component。

可是它沒有忘記 user,重新變回:

null

而是還記得:

{ name: 'Anthony' }

這件事情就是我們之後會碰到的 state preservation

今天先把它翻成白話:

React 重新算畫面時,還記得之前的 state。


今天要記住的東東

const [user, setUser] = useState(null)

現在可以拆成:

useState
→ React 提供的 Hook
→ 真正把「state」這個機制帶進來的地方

null
→ state 的初始值
→ 一開始還沒登入

user
→ 目前這份 state 的值
→ 現在的會員資料

setUser
→ 更新這份 state 的 function

[]
→ JavaScript Array 解構
→ 把 useState 回傳的兩個東西分別取出來

然後:

setUser({
  name: 'Anthony'
})

就是:

把登入狀態更新成 Anthony

好累Q_Q 每天都在跟時間賽跑欸...有了孩子之後一下子就快12點了...我想在學校真的是最幸福的事情。(中年男子的哀傷?


上一篇
Day 15|Figma 裡的 Gap、Fill、Hug,到了 React 到底怎麼變成 Tailwind?
下一篇
Day 17|onClick={login} 為什麼不用寫成 login()?
系列文
JavaScript為什麼筆記本20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言