ReactJs的Hooks簡介

banq發表於2018-11-02

在ReactConf上,React團隊提出了一種使用React實現互動式元件的新方法,稱為Hooks
他們釋出了一個RFC版本,在本文中,我們將研究如何實現這樣的功能。

開始準備工作:
npx create-react-app react-hooks
cd react-hooks
npm i react@next react-dom@next
npm start

讓我們建立一個新元件signin.js:

import React from 'react';

function Signin(props) {
    return <button
        onClick={props.isSignin ? props.Signout : props.Signin} >
        {props.isSignin ? "Signout" : "Sign in"}</button>
}


export default Signin;


counter.js

import React from 'react';

export default (props) => {

    return (
        <div>
        <h1> {props.value}</h1>
        <button onClick={props.Increment} >Increment</button>
        <button onClick={props.Decrement} >Decrement</button>
        </div>
    )

}


Hooks鉤子是一種幫助我們使用react特徵的功能
例如,在下面的程式碼中,useState鉤子用於在功能元件中新增狀態。
App.js

import React, { useState } from 'react';
import './App.css';
import Signin from './signin';
import Counter from './counter';

function App(props) {

   console.log(useState(0));

  return (
    <div className="App">
      <header className="App-header">
      </header>
    </div>
  );

}

export default App;


在上面的程式碼中,我們透過日誌輸出初始狀態0的useState鉤子。

useState掛鉤返回具有兩個元素的陣列,這兩個元素是當前狀態和用於更新狀態的函式。讓我們使用陣列解構的兩個元素。

import React, { useState } from 'react';
import './App.css';
import Signin from './signin';
import Counter from './counter';

function App(props) {

  const [value, Setvalue] = useState(0);

  function Incvalue() {
    return Setvalue(value + 1)
  }

  function Decvalue() {
    return Setvalue(value - 1)
  }

  return (
    <div className="App">
      <header className="App-header">
        <Counter value={value} Increment={Incvalue} Decrement={Decvalue} />
      </header>
    </div>
  );

}

export default App;
<p class="indent">


這裡使用一個簡單的函式呼叫useState,useState鉤子用於在功能元件中新增狀態。我們能獲得當前狀態,我們可以更改狀態,使用新狀態值重新渲染元件。Incvalue和Decvalue函式能夠改變value的數值狀態。

自定義React鉤子
自定義反應鉤只是javascript函式,以“use”一詞開頭。
讓我們建立自己的反應自定義鉤子。
status.js

import { useState } from 'react';

function useSigninStatus(status) {

    const [isSignin, setSignin] = useState(status);

    function Signin() {
        setSignin(true)
    }

    function Signout() {
        setSignin(false)
    }
    return {
        isSignin,
        Signin,
        Signout,
    }
}

export default useSigninStatus;

<p class="indent">


如何使用自定義反應鉤?以下程式碼是兩種鉤子一起使用

import React, { useState, useEffect } from 'react';
import './App.css';
import Signin from './signin';
import Counter from './counter';
import useSigninStatus from './status';

function App(props) {

  const [value, Setvalue] = useState(0);

  let status = useSigninStatus(false);

  function Incvalue() {
    return Setvalue(value + 1)
  }

  function Decvalue() {
    return Setvalue(value - 1)
  }

  return (
    <div className="App">
      <header className="App-header">
        <Signin {...status} />
        <Counter isSignin={status.isSignin} value={value} Increment={Incvalue} 
         Decrement={Decvalue} />
      </header>
    </div>
  );

}

export default App;
<p class="indent">


原始碼:程式碼庫

實際的鉤子內部函式如下所示,只是原理展示:

let globalHooks;
function useState(defaultValue) {
  let hookData = globalHooks.get(useState);

  if (!hookData) hookData = { calls: 0, store: [] };

  if (hookData.store[hookData.calls] === undefined)
    hookData.store[hookData.calls] = defaultValue;

  let value = hookData.store[hookData.calls];

  let calls = hookData.calls;
  let setValue = function(newValue) {
    hookData.store[calls] = newValue;
    hookData.render();
  };

  hookData.calls += 1;
  globalHooks.set(useState, hookData);

  return [value, setValue];
}



一步步分析:
  • 在第一次呼叫時應該返回defaultValue。
  • 它試圖從globalHooks全域性變數中獲取最後一次執行的狀態。在呼叫元件函式之前透過run函式設定Map物件。Map應該有上次執行後的資料,否則需要建立自己的資料hookData。
  • hookData.store是一個陣列,用於儲存上次呼叫的hookData.calls值,該值用於跟蹤此函式被我們的元件呼叫的程度。
  • 透過hookData.store[hookData.calls],我們可以抓住呼叫的最後一個儲存值; 如果它不存在我們必須使用defaultValue。
  • setValue回撥用於單擊按鈕時更新我們的資料值,例如。當點選一個按鈕,會呼叫calls,因此它知道setState函式呼叫屬於哪個calls。然後使用hookData.render回撥,啟動所有元件的重新呈現。
  • hookData.calls計數器增加。
  • hookData被儲存在globalHooks變數中,因此元件函式返回後,可透過render函式使用。




 

相關文章