国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

淺談React Hooks

yearsj / 1513人閱讀

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

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

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

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

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

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

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

特性

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

State Hook

最基本的應用如下:

import React, { useState } from "react"

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

  return (
    

You have clicked {count} times

) }

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

再看看有多個“local state”的情況:

import React, { useState } from "react"

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

  return (
    

name: {name}

age: {age}

) }

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

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的時候的執行順序都保持一致,否則就會出現錯誤。這也是React hooks rule中必須在top level使用hooks的由來——條件,遍歷等語句都有可能會改變hooks執行的順序。

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的函數(effect)中做了一些"side effect",在class component中我們通常會在componentDidMount,componentDidUpdate中去做這些事情。另外在class component中,需要在componentDidMount中訂閱,在componentWillUnmount中取消訂閱,這樣將一件事拆成兩件事做,不僅可讀性低,還容易產生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發生變化,則會導致訂閱和取消的id不一致,如需解決需要在componentDidUpdate中先取消訂閱舊的再訂閱新的,代碼非常冗余。而useEffect hook在這一點上是渾然天成的。另外effect函數在每次render時都是新創建的,這其實是有意而為之,因為這樣才能取得最新的state值。

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

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復用的問題,如上面例子中的FriendStatus,在一個聊天應用中可能多個組件都需要知道好友的在線狀態,將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復用的是stateful logic,而不是state本身。另外custom hook必須以use開頭來命名,這樣linter工具才能正確檢測其是否符合規范。

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

    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維護類似于class component中實例屬性的變量:

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

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

    function Counter() {
      const [count, setCount] = useState(0)
    
      const prevCountRef = useRef()
      useEffect(() => {
        prevCountRef.current = count    // 由于useEffect中的函數是在render完成之后異步執行的,所以在每次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

    文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

    轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/102216.html

    相關文章

    • 淺談reacthooks閉包陷阱

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

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

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

      william 評論0 收藏0
    • 淺談ReactFiber

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

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

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

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

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

      Lin_YT 評論0 收藏0

    發表評論

    0條評論

    yearsj

    |高級講師

    TA的文章

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