iT邦幫忙

2021 iThome 鐵人賽

DAY 5
0
Modern Web

我不會測試,所以寫Jest與React Testing Library系列 第 5

Day 5 hook的前奏 useState

這篇是在講React的測試,所以就拿個幾天篇幅來講hooks,React在v16.8之後開始支援hook,那就拿一些較常用的hook來介紹吧.

TL;DR

useState

先來一段程式吧,這邊我就不講class component時期的state的設計,應該大家都會吧?XDD

import { useState } from 'react';

const [count, setCount] = useState(0)

簡單的敘述一下,useState(0)裡面的0是initial Value,他的型別可以是:

  1. Primitive value → useState(' ' or 0 or true ...etc)
  2. Object → useState({} or [])
  3. Function → useState(() ⇒ {});

就如同我上面code所顯示的,state共有2種型別1種function可以設定,其中可以是primtive value or object以及callback可以設定,那我們設定完了值到哪了呢? 以範例為例就是[count, 忽略] ← 所以我們初始狀態0可以從count這個variable 取得,那我們如何更改count的值呢,這時候就可以用第二個setCount 這個setter來更改,但在講設定狀態之前,我們要講一下lazy state

大家想像一下如果初始化的值要運算很久怎辦

function caculate() {
	....假裝一下 可能有幾百行 
}

const App: FC = () => {
	const [info, setHeavyInfo] = useState(caculate())
}

這樣寫你的網頁一定爆幹強很硬,因為你的網頁每次render都要跑幾百行initialize;

function caculate() {
	....as above
}

const App: FC = () => {
	const [info, setHeavyInfo] = useState(() => caculate());
}

如果這樣寫,只會initialize 一開始render那一次,接下來講到setCount的setter

function handleUpdateCount() {
	setCount(prevCount => prevCount + 1);
} -> 這邊會牽扯到一個觀念 batch update

setter設定完之後整個component會re-render,當我們使用setState大家其實可以發現一件事情就是如果程式用以下的寫法:

function handleUpdateCount() {
	setCount(count+1);
	setCount(count+1);
	setCount(count+1);
}

大家會發現,為...為什麼還是+1而已

"Currently (React 16 and earlier), only updates inside React event handlers are batched by default" , according to Dan Abramov.

因為在一個function同時執行setCount是會batching update的所以只會更新只會觸發一次render 所以是+1,如果要修正這個問題有兩個解決方案.

  1. 使用updated function
  2. 使用useReducer

(1)啊第一個解法就是

function handleUpdateCount() {
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
    setCount(prevCount => prevCount + 1);
  }

執行時每次都會取得前一個的狀態

(2) useReducer大家自己去看官方文件

接下來無聊,如何自己寫一個useState

let state;

function render() {
	ReactDOM.render(<App />, document.getElementById('root'));
}

function useState(initialState) {
	state = state || initialState;

	function setState(newState) {
		state = newState;
		render()
	}

	return [state, setState];
}

render()

上一篇
Day 4 jest的生命週期
下一篇
Day 6 hook的前奏useEffect
系列文
我不會測試,所以寫Jest與React Testing Library30

尚未有邦友留言

立即登入留言