真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

react中一共有多少個(gè)hooks

這篇文章主要介紹了react中一共有多少個(gè)hooks,具有一定借鑒價(jià)值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個(gè)行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價(jià)值的長期合作伙伴,公司提供的服務(wù)項(xiàng)目有:申請域名網(wǎng)站空間、營銷軟件、網(wǎng)站建設(shè)、康巴什網(wǎng)站維護(hù)、網(wǎng)站推廣。

react共有9個(gè)hooks:useState、useEffect、useContext、useReducer、useCallback、useMemo、useRef、useImperativeHandle、useLayoutEffect。

本教程操作環(huán)境:Windows7系統(tǒng)、react17.0.1版、Dell G3電腦。

React Hooks(總共9個(gè))

在 React 的世界中,有容器組件和 UI 組件之分,在 React Hooks 出現(xiàn)之前,UI 組件我們可以使用函數(shù),無狀態(tài)組件來展示 UI,而對于容器組件,函數(shù)組件就顯得無能為力,我們依賴于類組件來獲取數(shù)據(jù),處理數(shù)據(jù),并向下傳遞參數(shù)給 UI 組件進(jìn)行渲染。在我看來,使用 React Hooks 相比于從前的類組件有以下幾點(diǎn)好處:

  • 代碼可讀性更強(qiáng),原本同一塊功能的代碼邏輯被拆分在了不同的生命周期函數(shù)中,容易使開發(fā)者不利于維護(hù)和迭代,通過 React Hooks 可以將功能代碼聚合,方便閱讀維護(hù)

  • 組件樹層級變淺,在原本的代碼中,我們經(jīng)常使用 HOC/render props 等方式來復(fù)用組件的狀態(tài),增強(qiáng)功能等,無疑增加了組件樹層數(shù)及渲染,而在 React Hooks 中,這些功能都可以通過強(qiáng)大的自定義的 Hooks 來實(shí)現(xiàn)

React 在 v16.8 的版本中推出了 React Hooks 新特性,雖然社區(qū)還沒有最佳實(shí)踐如何基于 React Hooks 來打造復(fù)雜應(yīng)用(至少我還沒有),憑借著閱讀社區(qū)中大量的關(guān)于這方面的文章,下面我將通過十個(gè)案例來幫助你認(rèn)識理解并可以熟練運(yùn)用 React Hooks 大部分特性。

1、useState 保存組件狀態(tài)

在類組件中,我們使用 this.state 來保存組件狀態(tài),并對其修改觸發(fā)組件重新渲染。比如下面這個(gè)簡單的計(jì)數(shù)器組件,很好詮釋了類組件如何運(yùn)行:

import React from "react";
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0,
      name: "alife"
    };
  }
  render() {
    const { count } = this.state;
    return (
      

        Count: {count}          this.setState({ count: count + 1 })}>+          this.setState({ count: count - 1 })}>-       

    );   } }

一個(gè)簡單的計(jì)數(shù)器組件就完成了,而在函數(shù)組件中,由于沒有 this 這個(gè)黑魔法,React 通過 useState 來幫我們保存組件的狀態(tài)。

import React, { useState } from "react";
function App() {
  const [obj, setObject] = useState({
    count: 0,
    name: "alife"
  });
  return (
    
      Count: {obj.count}
       setObject({ ...obj, count: obj.count + 1 })}>+
       setObject({ ...obj, count: obj.count - 1 })}>-
    

  ); }

通過傳入 useState 參數(shù)后返回一個(gè)帶有默認(rèn)狀態(tài)和改變狀態(tài)函數(shù)的數(shù)組。通過傳入新狀態(tài)給函數(shù)來改變原本的狀態(tài)值。值得注意的是 useState 不幫助你處理狀態(tài),相較于 setState 非覆蓋式更新狀態(tài),useState 覆蓋式更新狀態(tài),需要開發(fā)者自己處理邏輯。(代碼如上)

似乎有個(gè) useState 后,函數(shù)組件也可以擁有自己的狀態(tài)了,但僅僅是這樣完全不夠。

2、useEffect 處理副作用

函數(shù)組件能保存狀態(tài),但是對于異步請求,副作用的操作還是無能為力,所以 React 提供了 useEffect 來幫助開發(fā)者處理函數(shù)組件的副作用,在介紹新 API 之前,我們先來看看類組件是怎么做的:

import React, { Component } from "react";
class App extends Component {
  state = {
    count: 1
  };
  componentDidMount() {
    const { count } = this.state;
    document.title = "componentDidMount" + count;
    this.timer = setInterval(() => {
      this.setState(({ count }) => ({
        count: count + 1
      }));
    }, 1000);
  }
  componentDidUpdate() {
    const { count } = this.state;
    document.title = "componentDidMount" + count;
  }
  componentWillUnmount() {
    document.title = "componentWillUnmount";
    clearInterval(this.timer);
  }
  render() {
    const { count } = this.state;
    return (
      

        Count:{count}          clearInterval(this.timer)}>clear       

    );   } }

在例子中,組件每隔一秒更新組件狀態(tài),并且每次觸發(fā)更新都會(huì)觸發(fā) document.title 的更新(副作用),而在組件卸載時(shí)修改 document.title(類似于清除)

從例子中可以看到,一些重復(fù)的功能開發(fā)者需要在 componentDidMount 和 componentDidUpdate 重復(fù)編寫,而如果使用 useEffect 則完全不一樣。

import React, { useState, useEffect } from "react";
let timer = null;
function App() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = "componentDidMount" + count;
  },[count]);

  useEffect(() => {
    timer = setInterval(() => {
      setCount(prevCount => prevCount + 1);
    }, 1000);
    // 一定注意下這個(gè)順序:
    // 告訴react在下次重新渲染組件之后,同時(shí)是下次執(zhí)行上面setInterval之前調(diào)用
    return () => {
      document.title = "componentWillUnmount";
      clearInterval(timer);
    };
  }, []);
  return (
    

      Count: {count}        clearInterval(timer)}>clear     

  ); }

我們使用 useEffect 重寫了上面的例子,useEffect 第一個(gè)參數(shù)接收一個(gè)函數(shù),可以用來做一些副作用比如異步請求,修改外部參數(shù)等行為,而第二個(gè)參數(shù)稱之為dependencies,是一個(gè)數(shù)組,如果數(shù)組中的值變化才會(huì)觸發(fā) 執(zhí)行useEffect 第一個(gè)參數(shù)中的函數(shù)。返回值(如果有)則在組件銷毀或者調(diào)用函數(shù)前調(diào)用。

  • 1.比如第一個(gè) useEffect 中,理解起來就是一旦 count 值發(fā)生改變,則修改 documen.title 值;

  • 2.而第二個(gè) useEffect 中傳遞了一個(gè)空數(shù)組[],這種情況下只有在組件初始化或銷毀的時(shí)候才會(huì)觸發(fā),用來代替 componentDidMount 和 componentWillUnmount,慎用;

    1. 還有另外一個(gè)情況,就是不傳遞第二個(gè)參數(shù),也就是useEffect只接收了第一個(gè)函數(shù)參數(shù),代表不監(jiān)聽任何參數(shù)變化。每次渲染DOM之后,都會(huì)執(zhí)行useEffect中的函數(shù)。

基于這個(gè)強(qiáng)大 Hooks,我們可以模擬封裝出其他生命周期函數(shù),比如 componentDidUpdate 代碼十分簡單

function useUpdate(fn) {
    // useRef 創(chuàng)建一個(gè)引用
    const mounting = useRef(true);
    useEffect(() => {
      if (mounting.current) {
        mounting.current = false;
      } else {
        fn();
      }
    });
}

現(xiàn)在我們有了 useState 管理狀態(tài),useEffect 處理副作用,異步邏輯,學(xué)會(huì)這兩招足以應(yīng)對大部分類組件的使用場景。

3、useContext 減少組件層級

上面介紹了 useState、useEffect 這兩個(gè)最基本的 API,接下來介紹的 useContext 是 React 幫你封裝好的,用來處理多層級傳遞數(shù)據(jù)的方式,在以前組件樹種,跨層級祖先組件想要給孫子組件傳遞數(shù)據(jù)的時(shí)候,除了一層層 props 往下透傳之外,我們還可以使用 React Context API 來幫我們做這件事,舉個(gè)簡單的例子:

const { Provider, Consumer } = React.createContext(null);
function Bar() {
  return {color => 

{color}

}
; } function Foo() {   return ; } function App() {   return (                    ); }

通過 React createContext 的語法,在 APP 組件中可以跨過 Foo 組件給 Bar 傳遞數(shù)據(jù)。而在 React Hooks 中,我們可以使用 useContext 進(jìn)行改造。

const colorContext = React.createContext("gray");
function Bar() {
  const color = useContext(colorContext);
  return 

{color}

; } function Foo() {   return ; } function App() {   return (                    ); }

傳遞給 useContext 的是 context 而不是 consumer,返回值即是想要透傳的數(shù)據(jù)了。用法很簡單,使用 useContext 可以解決 Consumer 多狀態(tài)嵌套的問題。

function HeaderBar() {
  return (
    
      {user =>
        
          {notifications =>
            
              Welcome back, {user.name}!               You have {notifications.length} notifications.             
          }       }     
  ); }

而使用 useContext 則變得十分簡潔,可讀性更強(qiáng)且不會(huì)增加組件樹深度。

function HeaderBar() {
  const user = useContext(CurrentUser);
  const notifications = useContext(Notifications);
  return (
    
      Welcome back, {user.name}!       You have {notifications.length} notifications.     
  ); }

4、useReducer

useReducer 這個(gè) Hooks 在使用上幾乎跟 Redux/React-Redux 一模一樣,唯一缺少的就是無法使用 redux 提供的中間件。我們將上述的計(jì)時(shí)器組件改寫為 useReducer,

import React, { useReducer } from "react";
const initialState = {
  count: 0
};
function reducer(state, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + action.payload };
    case "decrement":
      return { count: state.count - action.payload };
    default:
      throw new Error();
  }
}
function App() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
       dispatch({ type: "increment", payload: 5 })}>
        +
      
       dispatch({ type: "decrement", payload: 5 })}>
        -
      
    
  );
}

用法跟 Redux 基本上是一致的,用法也很簡單,算是提供一個(gè) mini 的 Redux 版本。

5、useCallback 記憶函數(shù)

在類組件中,我們經(jīng)常犯下面這樣的錯(cuò)誤:

class App {
    render() {
        return 

             { console.log('do something'); }}  />         

;     } }

這樣寫有什么壞處呢?一旦 App 組件的 props 或者狀態(tài)改變了就會(huì)觸發(fā)重渲染,即使跟 SomeComponent 組件不相關(guān),由于每次 render 都會(huì)產(chǎn)生新的 style 和 doSomething(因?yàn)橹匦聄ender前后, style 和 doSomething分別指向了不同的引用),所以會(huì)導(dǎo)致 SomeComponent 重新渲染,倘若 SomeComponent 是一個(gè)大型的組件樹,這樣的 Virtual Dom 的比較顯然是很浪費(fèi)的,解決的辦法也很簡單,將參數(shù)抽離成變量。

const fontSizeStyle = { fontSize: 14 };
class App {
    doSomething = () => {
        console.log('do something');
    }
    render() {
        return 

                     

;     } }

在類組件中,我們還可以通過 this 這個(gè)對象來存儲(chǔ)函數(shù),而在函數(shù)組件中沒辦法進(jìn)行掛載了。所以函數(shù)組件在每次渲染的時(shí)候如果有傳遞函數(shù)的話都會(huì)重渲染子組件。

function App() {
  const handleClick = () => {
    console.log('Click happened');
  }
  return Click Me;
}

這里多說一句,一版把函數(shù)式組件理解為class組件render函數(shù)的語法糖,所以每次重新渲染的時(shí)候,函數(shù)式組件內(nèi)部所有的代碼都會(huì)重新執(zhí)行一遍。所以上述代碼中每次render,handleClick都會(huì)是一個(gè)新的引用,所以也就是說傳遞給SomeComponent組件的props.onClick一直在變(因?yàn)槊看味际且粋€(gè)新的引用),所以才會(huì)說這種情況下,函數(shù)組件在每次渲染的時(shí)候如果有傳遞函數(shù)的話都會(huì)重渲染子組件。

而有了 useCallback 就不一樣了,你可以通過 useCallback 獲得一個(gè)記憶后的函數(shù)。

function App() {
  const memoizedHandleClick = useCallback(() => {
    console.log('Click happened')
  }, []); // 空數(shù)組代表無論什么情況下該函數(shù)都不會(huì)發(fā)生改變
  return Click Me;
}

老規(guī)矩,第二個(gè)參數(shù)傳入一個(gè)數(shù)組,數(shù)組中的每一項(xiàng)一旦值或者引用發(fā)生改變,useCallback 就會(huì)重新返回一個(gè)新的記憶函數(shù)提供給后面進(jìn)行渲染。

這樣只要子組件繼承了 PureComponent 或者使用 React.memo 就可以有效避免不必要的 VDOM 渲染。

6、useMemo 記憶組件

useCallback 的功能完全可以由 useMemo 所取代,如果你想通過使用 useMemo 返回一個(gè)記憶函數(shù)也是完全可以的。

useCallback(fn, inputs) is equivalent to useMemo(() => fn, inputs).

所以前面使用 useCallback 的例子可以使用 useMemo 進(jìn)行改寫:

function App() {
  const memoizedHandleClick = useMemo(() => () => {
    console.log('Click happened')
  }, []); // 空數(shù)組代表無論什么情況下該函數(shù)都不會(huì)發(fā)生改變
  return Click Me;
}

唯一的區(qū)別是:**useCallback 不會(huì)執(zhí)行第一個(gè)參數(shù)函數(shù),而是將它返回給你,而 useMemo 會(huì)執(zhí)行第一個(gè)函數(shù)并且將函數(shù)執(zhí)行結(jié)果返回給你。**所以在前面的例子中,可以返回 handleClick 來達(dá)到存儲(chǔ)函數(shù)的目的。

所以 useCallback 常用記憶事件函數(shù),生成記憶后的事件函數(shù)并傳遞給子組件使用。而 useMemo 更適合經(jīng)過函數(shù)計(jì)算得到一個(gè)確定的值,比如記憶組件。

function Parent({ a, b }) {
  // Only re-rendered if `a` changes:
  const child1 = useMemo(() => , [a]);
  // Only re-rendered if `b` changes:
  const child2 = useMemo(() => , [b]);
  return (
    <>
      {child1}
      {child2}
    
  )
}

當(dāng) a/b 改變時(shí),child1/child2 才會(huì)重新渲染。從例子可以看出來,只有在第二個(gè)參數(shù)數(shù)組的值發(fā)生變化時(shí),才會(huì)觸發(fā)子組件的更新。

7、useRef 保存引用值

useRef 跟 createRef 類似,都可以用來生成對 DOM 對象的引用,看個(gè)簡單的例子:

import React, { useState, useRef } from "react";
function App() {
  let [name, setName] = useState("Nate");
  let nameRef = useRef();
  const submitButton = () => {
    setName(nameRef.current.value);
  };
  return (
    
      

{name}

      

                            Submit                

    

  ); }

useRef 返回的值傳遞給組件或者 DOM 的 ref 屬性,就可以通過 ref.current 值訪問組件或真實(shí)的 DOM 節(jié)點(diǎn),重點(diǎn)是組件也是可以訪問到的,從而可以對 DOM 進(jìn)行一些操作,比如監(jiān)聽事件等等。

當(dāng)然 useRef 遠(yuǎn)比你想象中的功能更加強(qiáng)大,useRef 的功能有點(diǎn)像類屬性,或者說您想要在組件中記錄一些值,并且這些值在稍后可以更改。

利用 useRef 就可以繞過 Capture Value 的特性??梢哉J(rèn)為 ref 在所有 Render 過程中保持著唯一引用,因此所有對 ref 的賦值或取值,拿到的都只有一個(gè)最終狀態(tài),而不會(huì)在每個(gè) Render 間存在隔離。

React Hooks 中存在 Capture Value 的特性:

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

  useEffect(() => {
    setTimeout(() => {
      alert("count: " + count);
    }, 3000);
  }, [count]);

  return (
    

      

You clicked {count} times

       setCount(count + 1)}>增加 count        setCount(count - 1)}>減少 count     

  ); }

先點(diǎn)擊增加button,后點(diǎn)擊減少button,3秒后先alert 1,后alert 0,而不是alert兩次0。這就是所謂的 capture value 的特性。而在類組件中 3 秒后輸出的就是修改后的值,因?yàn)檫@時(shí)候** message 是掛載在 this 變量上,它保留的是一個(gè)引用值**,對 this 屬性的訪問都會(huì)獲取到最新的值。講到這里你應(yīng)該就明白了,useRef 創(chuàng)建一個(gè)引用,就可以有效規(guī)避 React Hooks 中 Capture Value 特性。

function App() {
  const count = useRef(0);

  const showCount = () => {
    alert("count: " + count.current);
  };

  const handleClick = number => {
    count.current = count.current + number;
    setTimeout(showCount, 3000);
  };

  return (
    

      

You clicked {count.current} times

       handleClick(1)}>增加 count        handleClick(-1)}>減少 count     

  ); }

只要將賦值與取值的對象變成 useRef,而不是 useState,就可以躲過 capture value 特性,在 3 秒后得到最新的值。

8、useImperativeHandle 透傳 Ref

通過 useImperativeHandle 用于讓父組件獲取子組件內(nèi)的索引

import React, { useRef, useEffect, useImperativeHandle, forwardRef } from "react";
function ChildInputComponent(props, ref) {
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => inputRef.current);
  return ;
}
const ChildInput = forwardRef(ChildInputComponent);
function App() {
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current.focus();
  }, []);
  return (
    

           

  ); }

通過這種方式,App 組件可以獲得子組件的 input 的 DOM 節(jié)點(diǎn)。

9、useLayoutEffect 同步執(zhí)行副作用

大部分情況下,使用 useEffect 就可以幫我們處理組件的副作用,但是如果想要同步調(diào)用一些副作用,比如對 DOM 的操作,就需要使用 useLayoutEffect,useLayoutEffect 中的副作用會(huì)在 DOM 更新之后同步執(zhí)行。

function App() {
  const [width, setWidth] = useState(0);
  useLayoutEffect(() => {
    const title = document.querySelector("#title");
    const titleWidth = title.getBoundingClientRect().width;
    console.log("useLayoutEffect");
    if (width !== titleWidth) {
      setWidth(titleWidth);
    }
  });
  useEffect(() => {
    console.log("useEffect");
  });
  return (
    

      hello       

{width}

    

  ); }

在上面的例子中,useLayoutEffect 會(huì)在 render,DOM 更新之后同步觸發(fā)函數(shù),會(huì)優(yōu)于 useEffect 異步觸發(fā)函數(shù)。

(1) useEffect和useLayoutEffect有什么區(qū)別?

簡單來說就是調(diào)用時(shí)機(jī)不同,useLayoutEffect和原來componentDidMount&componentDidUpdate一致,在react完成DOM更新后馬上同步調(diào)用的代碼,會(huì)阻塞頁面渲染。而useEffect是會(huì)在整個(gè)頁面渲染完才會(huì)調(diào)用的代碼。

官方建議優(yōu)先使用useEffect

However, we recommend starting with useEffect firstand only trying useLayoutEffect if that causes a problem.

在實(shí)際使用時(shí)如果想避免頁面抖動(dòng)(在useEffect里修改DOM很有可能出現(xiàn))的話,可以把需要操作DOM的代碼放在useLayoutEffect里。關(guān)于使用useEffect導(dǎo)致頁面抖動(dòng)。

不過useLayoutEffect在服務(wù)端渲染時(shí)會(huì)出現(xiàn)一個(gè)warning,要消除的話得用useEffect代替或者推遲渲染時(shí)機(jī)。

感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享的“react中一共有多少個(gè)hooks”這篇文章對大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,更多相關(guān)知識等著你來學(xué)習(xí)!


分享名稱:react中一共有多少個(gè)hooks
當(dāng)前URL:http://weahome.cn/article/gjhhes.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部