react隨筆之hooks(一)

Hooks使用條件

目前用create-react-app腳手架創建的項目,react和react-dom版本爲^16.7.0,該版本還未支持hooks的使用,未升級使用會報錯誤:TypeError: Object(...) is not a function。

升級react的版本很簡單,在該項目目錄下執行如下語句即可。

yarn add react@next react-dom@next

完成後可查看package.json文件是否升級成功,該文章代碼是基於react react-dom ^16.8.0-alpha.1版本運行的。

Hooks是寫在React function裏面的,與之前的class不同,就像官網的例子裏一樣。我們可以這樣

const Example = (props) => {
  // You can use Hooks here!
  return <div />;
}

或者這樣

function Example(props) {
  // You can use Hooks here!
  return <div />;
}

又或者直接

export default (props) => {
  // You can use Hooks here!
  return <div />;
}

總之

  • 只在 React Functions 調用 Hooks
  • 只在頂層調用Hook,不能在循環,條件或嵌套函數中調用Hook

useState

首先需要import一下useState

import React, { useState } from "react";

然後我們就可以在function裏面使用了,以count爲例,方法如下

const [count, setCount] = useState(0);

count是state,0是count的初始值,setCount是設置count的一個函數(函數名不一定要是setXxx,也可以如sCount等,但不建議這麼做),setCount()等效於👇

setCount = (count) => {
    this.setState({
      count
    })
  }

useState只能在頂層調用,不能在循環,條件或嵌套函數中調用,因爲useSate是基於數組的實現的,而他們的下標是根據useState出現順序決定的,假設判斷語句中存在useState,當判斷不成立時(即不執行判斷包裹的代碼時),useState會因爲下標錯亂而出錯。想了解更多可看React hooks: not magic, just arrays (需科學上網)或官網的Rules of Hooks

具體使用如下:

import React, { useState } from 'react';
function Cunter() {
  const [count, setCount] = useState(0);

  return (
    <div className="count-box">
      <h1 className="title">點了{count}次</h1>
      <button onClick={() => {setCount(count + 1);}}>Click Me!</button>
    </div>
  );
}
export default Cunter;

useEffect

useEffect結合了componentWillMount、componentDidMount和componentWillUnmount的特性。useEffect可以傳入兩個參數,第一個是必選參數,爲function類型,是effect執行的內容,第二爲可選參數,爲數組類型,是判斷是否執行該effect,若第二參數的數值發生變化,則執行。

  useEffect(()=>{
    console.log('current count:'+count)
  })

👆組件加載時、state變化時,都會執行console.log

  useEffect(()=>{
    console.log('first effect count:'+count)//new count
    return function cleanup(){console.log('first effect return count:'+count)}//old count
  })

👆組件加載時執行第一個console.log,state變化時,會先執行return的cleanup函數,打印上一次運行時的count,再執行第一個console.log。
注意!這裏上一個運行時的意思是該effect上一次執行時的state,並非是上一個state,這麼說有點繞,看一下這個例子👇

  useEffect(()=>{
    console.log('third effect count:'+count)
    return function cleanup(){console.log('third effect return count:'+count)}
  },[count>4?1:0])

👆假設你點擊了8次,當你點第五次時,此時第二參數的內容從0變成了1,所以執行了該effect,打印了

third effect return count:0
third effect count:5

之後再也不執行該effect,直到將這個組件卸載時,纔會執行該effect的cleanup函數,但打印的並不是想象中的 8 ,而是

third effect return count:5

既該effect的上一次運行時的state。


因爲該特性,所以並不推薦第二參數傳遞[]來模擬componentDidMount 和componentWillUnmount,引用官網的原話

While passing [] is closer to the familiar componentDidMount and componentWillUnmount mental model, we suggest not making it a habit because it often leads to bugs, as discussed above. Don’t forget that React defers running useEffect until after the browser has painted, so doing extra work is less of a problem.

完整代碼👇

//Count.jsx
import React, { useState, useEffect } from "react";

function Cunter() {
  const [count, setCount] = useState(0);

  useEffect(()=>{
    console.log('first effect count:'+count)
    return function cleanup(){console.log('first effect return cleanup')}
  },[])

  useEffect(()=>{
    console.log('second effect, current count:'+count)//new count
    return function cleanup(){console.log('second effect return count:'+count)}//old count
  })

  useEffect(()=>{
    console.log('third effect count:'+count)
    return function cleanup(){console.log('third effect return count:'+count)}
  },[count>4?1:0])

  return (
    <div className="count-box">
      <h1 className="title">點了{count}次</h1>
      <button onClick={() => {setCount(count + 1);}}>Click Me!</button>
    </div>
  );
}

export default Cunter;

//App.jsx
import React, { Component } from "react";
import Cunter from "./Cunter";
class App extends Component {
  constructor(props) {
    super(props);
    this.state = { show: true };
  }
  render() {
    return (
      <div>
        {this.state.show ? <Cunter /> : <p>cleanup</p>}
        <br/>
        <button  onClick={() => {this.setState({ show: false })}}>cleanup</button>
      </div>
    );
  }
}

export default App;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章