成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

淺談React Hooks

yearsj / 1520人閱讀

摘要:另外也不利于組件的,及。所以在使用時,盡量將相關(guān)聯(lián)的,會共同變化的值放入一個。有同學(xué)可能會想,每次后都會執(zhí)行,這樣會不會對性能造成影響。另外必須以開頭來命名,這樣工具才能正確檢測其是否符合規(guī)范。

由于工作的原因我已經(jīng)很長時間沒接觸過React了。前段時間圈子里都在討論React Hooks,出于好奇也學(xué)習(xí)了一番,特此整理以加深理解。
緣由

在web應(yīng)用無所不能的9012年,組成應(yīng)用的Components也越來越復(fù)雜,冗長而難以復(fù)用的代碼給開發(fā)者們造成了很多麻煩。比如:

難以復(fù)用stateful的代碼,render props及HOC雖然解決了問題,但對組件的包裹改變了組件樹的層級,存在冗余;

在ComponentDidMount、ComponentDidUpdate、ComponentWillUnmount等生命周期中做獲取數(shù)據(jù),訂閱/取消事件,操作ref等相互之間無關(guān)聯(lián)的操作,而把訂閱/取消這種相關(guān)聯(lián)的操作分開,降低了代碼的可讀性;

與其他語言中的class概念差異較大,需要對事件處理函數(shù)做bind操作,令人困擾。另外class也不利于組件的AOT compile,minify及hot loading。

在這種背景下,React在16.8.0引入了React Hooks。

特性

主要介紹state hook,effect hook及custom hook

State Hook

最基本的應(yīng)用如下:

import React, { useState } from "react"

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

  return (
    

You have clicked {count} times

) }

調(diào)用useState,傳入初始值,通過數(shù)組的結(jié)構(gòu)賦值得到獨立的local state count,及setCount。count可以理解為class component中的state,可見這里的state不局限于對象,可以為number,string,當(dāng)然也可以是一個對象。而setCount可以理解為class component中的setState,不同的是setState會merge新老state,而hook中的set函數(shù)會直接替換,這就意味著如果state是對象時,每次set應(yīng)該傳入所有屬性,而不能像class component那樣僅傳入變化的值。所以在使用useState時,盡量將相關(guān)聯(lián)的,會共同變化的值放入一個object。

再看看有多個“l(fā)ocal state”的情況:

import React, { useState } from "react"

function person() {
  const [name, setName] = useState("simon")
  const [age, setAge] = useState(24)

  return (
    

name: {name}

age: {age}

) }

我們知道當(dāng)函數(shù)執(zhí)行完畢,函數(shù)作用域內(nèi)的變量都會銷毀,hooks中的state在component首次render后被React保留下來了。那么在下一次render時,React如何將這些保留的state與component中的local state對應(yīng)起來呢。這里給出一個簡單版本的實現(xiàn):

const stateArr = []
const setterArr = []
let cursor = 0
let isFirstRender = true

function createStateSetter(cursor) {
  return state => {
    stateArr[cursor] = state
  }
}

function useState(initState) {
  if (isFirstRender) {
    stateArr.push(initState)
    setterArr.push(createStateSetter(cursor))

    isFirstRender = false
  }

  const state = stateArr[cursor]
  const setter = setterArr[cursor]

  cursor++

  return [state, setter]
}

可以看出React需要保證多個hooks在component每次render的時候的執(zhí)行順序都保持一致,否則就會出現(xiàn)錯誤。這也是React hooks rule中必須在top level使用hooks的由來——條件,遍歷等語句都有可能會改變hooks執(zhí)行的順序。

Effect Hook
import React, { useState, useEffect } from "react"

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null)

  function handleStatusChange(status) {
    setIsOnline(status.isOnline)
  }

  // 基本寫法
  useEffect(() => {
    document.title = "Dom is ready"
  })

  // 需要取消操作的寫法
  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)

    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange)
    }
  })

  if (isOnline === null) {
    return "Loading..."
  }
  return isOnline ? "Online" : "Offline"
}

可以看到上面的代碼在傳入useEffect的函數(shù)(effect)中做了一些"side effect",在class component中我們通常會在componentDidMount,componentDidUpdate中去做這些事情。另外在class component中,需要在componentDidMount中訂閱,在componentWillUnmount中取消訂閱,這樣將一件事拆成兩件事做,不僅可讀性低,還容易產(chǎn)生bug:

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

  render() {
    if (this.state.isOnline === null) {
      return "Loading...";
    }
    return this.state.isOnline ? "Online" : "Offline";
  }
}

如上代碼,如果props中的friend.id發(fā)生變化,則會導(dǎo)致訂閱和取消的id不一致,如需解決需要在componentDidUpdate中先取消訂閱舊的再訂閱新的,代碼非常冗余。而useEffect hook在這一點上是渾然天成的。另外effect函數(shù)在每次render時都是新創(chuàng)建的,這其實是有意而為之,因為這樣才能取得最新的state值。

有同學(xué)可能會想,每次render后都會執(zhí)行effect,這樣會不會對性能造成影響。其實effect是在頁面渲染完成之后執(zhí)行的,不會阻塞,而在effect中執(zhí)行的操作往往不要求同步完成,除了少數(shù)如要獲取寬度或高度,這種情況需要使用其他的hook(useLayoutEffect),此處不做詳解。即使這樣,React也提供了控制的方法,及useEffect的第二個參數(shù)————一個數(shù)組,如果數(shù)組中的值不發(fā)生變化的話就跳過effect的執(zhí)行:

useEffect(() => {
  ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange)
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  }
}, [props.friend.id])
Custom Hook
A custom Hook is a JavaScript function whose name starts with ”use” and that may call other Hooks.

Custom Hook的使命是解決stateful logic復(fù)用的問題,如上面例子中的FriendStatus,在一個聊天應(yīng)用中可能多個組件都需要知道好友的在線狀態(tài),將FriendStatus抽象成這樣的hook:

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id)

  if (isOnline === null) {
    return "Loading..."
  }

  return isOnline ? "Online" : "Offline"
}

function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id)

  return (
    
  • {props.friend.name}
  • ) }

    FriendStatus和FriendListItem中的isOnline是獨立的,因custom hook復(fù)用的是stateful logic,而不是state本身。另外custom hook必須以use開頭來命名,這樣linter工具才能正確檢測其是否符合規(guī)范。

    除了以上三種hook,React還提供了useContext, useReducer, useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect, useDebugValue內(nèi)置hook,它們的用途可以參考官方文檔,這里我想多帶帶講講useRef。
    顧名思義,這個hook應(yīng)該跟ref相關(guān)的:

    function TextInputWithFocusButton() {
      const inputEl = useRef(null)
      const onButtonClick = () => {
        inputEl.current.focus()
      }
      return (
        <>
          
          
        
      )
    }

    來看看官方文檔上的說明:

    useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime    of the component.

    這句話告訴我們在組件的整個生命周期里,inputEl.current都是存在的,這擴展了useRef本身的用途,可以使用useRef維護(hù)類似于class component中實例屬性的變量:

    function Timer() {
      const intervalRef = useRef()
    
      useEffect(() => {
        const id = setInterval(() => {
          // ...
        })
        intervalRef.current = id
        return () => {
          clearInterval(intervalRef.current)
        }
      })
    
      // ...
    }

    這在class component中是理所當(dāng)然的,但不要忘記Timer僅僅是一個函數(shù),函數(shù)執(zhí)行完畢后函數(shù)作用域內(nèi)的變量將會銷毀,所以這里需要使用useRef來保持這個timerId。類似的useRef還可以用來獲取preState:

    function Counter() {
      const [count, setCount] = useState(0)
    
      const prevCountRef = useRef()
      useEffect(() => {
        prevCountRef.current = count    // 由于useEffect中的函數(shù)是在render完成之后異步執(zhí)行的,所以在每次render時prevCountRef.current的值為上一次的count值
      })
      const prevCount = prevCountRef.current
    
      return 

    Now: {count}, before: {prevCount}

    }
    參考文章&拓展閱讀

    React Hooks官方文檔

    React hooks: not magic, just arrays

    Why Isn’t X a Hook?

    Making Sense of React Hooks

    文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/102216.html

    相關(guān)文章

    • 淺談reacthooks閉包陷阱

        本文不會過多講解基礎(chǔ)知識,更多說的是在使用useRef如何能擺脫 這個 閉包陷阱 ?  react hooks 的閉包陷阱 基本每個開發(fā)員都有遇見,這是很令人抓狂的?! ?以下react示范demo,均為react 16.8.3 版本)  列一個具體的場景:  functionApp(){   const[count,setCount]=useState(1);   useEffect(()=...

      3403771864 評論0 收藏0
    • 淺談webpack之plugin,webpack-manifest-plugin源碼解讀

      摘要:注冊方法之后,當(dāng)執(zhí)行了當(dāng)前的,那么掛載正在當(dāng)前上的方法就會被執(zhí)行。比如在開始編譯之前,就能觸發(fā)鉤子,就用到了當(dāng)前的。上面都是前置知識,下面通過解讀一個源碼來鞏固下。先看一段簡單的源碼。,是眾多的的一個,官網(wǎng)的解釋是編譯創(chuàng)建之后,執(zhí)行插件。 通過解讀webpack-manifest-plugin,了解下plugin機制 先簡單說一下這個插件的功能,生成一份資源清單的json文件,如下 s...

      william 評論0 收藏0
    • 淺談ReactFiber

      摘要:什么是每一個都有一個對應(yīng)的,記錄這個節(jié)點的各種狀態(tài),是一鏈表的結(jié)構(gòu)的串聯(lián)起來。 1. 什么是fiber 每一個ReactElement都有一個對應(yīng)的fiber, 記錄這個節(jié)點的各種狀態(tài), fiber是一鏈表的結(jié)構(gòu)的串聯(lián)起來。showImg(https://segmentfault.com/img/bVbqVZR?w=540&h=708); 2. Fiber的組成 export type...

      yibinnn 評論0 收藏0
    • 精讀《React Hooks

      摘要:更容易將組件的與狀態(tài)分離。也就是只提供狀態(tài)處理方法,不會持久化狀態(tài)。大體思路是利用共享一份數(shù)據(jù),作為的數(shù)據(jù)源。精讀帶來的約定函數(shù)必須以命名開頭,因為這樣才方便做檢查,防止用判斷包裹語句。前端精讀幫你篩選靠譜的內(nèi)容。 1 引言 React Hooks 是 React 16.7.0-alpha 版本推出的新特性,想嘗試的同學(xué)安裝此版本即可。 React Hooks 要解決的問題是狀態(tài)共享,...

      kohoh_ 評論0 收藏0
    • 新上課程推薦:《React Hooks 案例詳解(React 進(jìn)階必備)》

      摘要:課程制作和案例制作都經(jīng)過精心編排。對于開發(fā)者意義重大,希望對有需要的開發(fā)者有所幫助。是從提案轉(zhuǎn)為正式加入的新特性。并不需要用繼承,而是推薦用嵌套。大型項目中模塊化與功能解耦困難。從而更加易于復(fù)用和獨立測試。但使用會減少這種幾率。 showImg(https://segmentfault.com/img/bVbpNRZ?w=1920&h=1080); 講師簡介 曾任職中軟軍隊事業(yè)部,參與...

      Lin_YT 評論0 收藏0

    發(fā)表評論

    0條評論

    最新活動
    閱讀需要支付1元查看
    <