到底React Hooks有何特別(二)?淺談useEffect及useReducer
2018-11-29
於本篇文章的上集,我們討論了useState
如何令Stateful React component
簡化良多,此篇主要討論的是如何使
用useEffect
。useEffect
可以簡化stateful logic,很多人都提到 React Hooks
有可能可以完全取代Redux
作為 React State
Management的標準,正因如此。
重溫
上集提到,使用useState
可以將原本class based component
變成簡單的 functional component
。
class Welcome extends React.Component{ constructor(props){ super(props); this.state = { counter: 0 } this.incrementCounter = this.incrementCounter.bind(this); } incrementCounter(){ this.setState(state=>({ counter : state.counter+1 })); } render(){ return ( <h1 onClick={this.incrementCounter}> Hello, {this.props.name} {this.state.counter} times </h1> ) } }
變成
function Welcome(props) { const [counter,setCounter] = useState(0); return <h1 onClick={()=>setCounter(counter=>counter+1)}> Hello, {props.name} {counter} times </h1>; }
UseEffect
此例子中並無諸如componentDidUpdate
、componentDidMount
、componentWillUnmount
等方法,React Hooks
到底如何有效於
function 中取代呢?答案就是運用 useEffect
。
舉例加上componentDidMount
及componentWillUnmount
,來初始化及重置counter。
class App extends React.Component { constructor(props) { super(props); this.state = { counter: 0 }; this.incrementCounter = this.incrementCounter.bind(this); } componentDidMount() { this.setState({ counter: 10 }); } componentWillUnmount() { this.setState({ counter: 0 }); } incrementCounter() { this.setState(state => ({ counter: state.counter + 1 })); } render() { return ( <h1 onClick={this.incrementCounter}> Hello, {this.props.name} {this.state.counter} times </h1> ); } }
componentDidMount
算是component的setup logic,當component一載入完成就會開始運行。
componentWillUnmount
算是component的teardown logic,當component臨缷載前開始運行。
以useEffect
方法寫,出乎意料簡潔:
function App(props) { const [counter, setCounter] = useState(0); useEffect(() => { setCounter(counter => 10); return () => { setCounter(counter => 0); }; }, []); return ( <h1 onClick={() => setCounter(counter => counter + 1)}> Hello, {props.name} {counter} times </h1> ); }
多出來的只是一段如下的代碼:
useEffect(()=>{ // componentDidMount is here! setCounter(counter=> 10); return ()=>{ // componentWillUnmount is here! setCounter(counter=>0) } },[])
第一個**setCounter(counter=>10)**是隨我們Welcome一起載入運行,而在return的function則是此effect的 teardown logic,也就是為清理
資源而寫的。你可能會問,那麼這段邏輯取代了 componentDidMount
、componentDidUpdate
、componentWillUnmount
那個呢?
- 原本應在
componentDidMount
的是 setCounter(counter=>10) - 原本應在
componentWillUnmount
的是 setCounter(counter=>0)
那componentDidUpdate
呢? 有趣的是,上面並沒有對應 componentDidUpdate
的地方,因為在useEffect
第二個參數,有一個empty
array。第二個參數是此effect的dependency,React會儲起每次這個array的數值,如果在下一次update的時候發現這個array改變了,就代表了
這個effect需要重新運行。由於一個empty array永遠都是一樣,所以我們這個useEffect只會運行一次!如果沒有了第二個參數,那就變成了
componentDidUpdate
+componentDidMount
了。
useEffect(()=>{ // componentDidMount is here! // componentDidUpdate is here! setCounter(counter=> 10); return ()=>{ // componentWillUnmount is here! setCounter(counter=>0) } });
有了dependency 這個參數,可以輕易做到相當reactive的UI,例如僅當props改變,這個effect才會跟著改變,我們可以輕易寫成這個樣子
useEffect(()=>{ // componentDidMount is here! // componentDidUpdate is here! setCounter(counter=> 10); return ()=>{ // componentWillUnmount is here! setCounter(counter=>0) } },[props]);
請留意第二個參數需要一個array。 以下是一個在Github Pages的live Example:
UseReducer
React Hooks
當然不只useState
及useEffect
兩個方法,還有一個備受注目的,就是useReducer
。 useReducer
是React團隊方便開
發者使用reducer pattern而加入。
要使用useReducer
,寫法也是非常簡單。
function counterReducer(state, action) { switch (action.type) { case "INCREMENT": return { counter: state.counter + 1 }; default: return { counter: 0 }; } } function App(props) { const [state, dispatch] = useReducer(counterReducer, { counter: 10 }); return ( <h1 onClick={() => dispatch({ type: "INCREMENT" })}> Hello, {props.name} {state.counter} times </h1> ); }
上面 counterReducer
是正常reducer的寫法,只有一個簡單action
,就是INCREMENT
。 useReducer
會return兩個數值,第一個就
是state,第二個就是對應reducer的dispatch function,所以當一運行dispatch({type:"INCREMENT"})
時,就會把counter加了1。
此段代碼於上面CodeSandbox裏面的index-reducer.js
之內。
總結
useEffect
及useReducer
都大大簡化了React寫複雜代碼的難度。當然順帶一提的時, React Hooks
還是處於實驗性質的功能,各位尚未可以
應用於現實世界的軟件上的。不過由於功能强大,有取代現有複雜框架之勢,相當可能廣泛使用。
Comments
Read More
到底React Hooks 有何特別?
2018-11-27
新近推出的React 16.7包括一個很有趣的功能,名字叫做React Hooks。看到這個名字,很多人會下意識認為是在講componentDidMount, componentDidUpdate等方法。但其實這些方法的正名是 React Lifecycle Method, 推出React Hooks是為了方便開發者多用functional component,但仍然能夠使用state及 props等重要功能。
好Programmer是怎樣煉成的?
2018-12-20
有一個大部份僱主都面對的難題,在芸芸履歷之中,如何萬中挑一,找到好programmer呢?聘請程式設計師很難,不像其他行業,打開 履歷就一目了然:有時履歷上滿滿証書的,其實連FizzBuzz也寫不了;有時看起來像個fresh graduate的,卻又有無限潛力。 如果你是一個要聘請程式設計師的僱主,你應該如何是好呢?
軟件工程及軟件工藝
2018-12-24
軟件工程是一個相當耳熟能詳的名詞,軟件工程(Software Engineering)由來已久,亦因此程式設計師(Programmer)又稱為軟件工程 師(Software Engineer)。
Web Technology為何征服世界?
2019-02-05
2007年,蘋果宣佈發佈第一代iPhone,標誌智能電話時代的開始;一年之後Android亦宣告面世,從此時起,智能電話的發展迅速,Mobile App成為軟件的代 名詞,筆者初初成為軟件工程師時,總有朋友詢問我是否正在開發Mobile App,縱使筆者的專業一直都是網頁及後端開發之上。而其時亦有不少預測,預測[網站將會被Mobile App完全取代](https://searchenginewatch.com/sew/opinion/2414336/the-final-hurdle-is-cleared-apps-will-replace-websites)。網站所用的HTML、CSS、JS等,亦將成為歷史,送入博物館之內。