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

資訊專欄INFORMATION COLUMN

十個案例學(xué)會 React Hooks

williamwen1986 / 2051人閱讀

摘要:在線傳遞給的是而不是,返回值即是想要透傳的數(shù)據(jù)了。所以函數(shù)組件在每次渲染的時候如果有傳遞函數(shù)的話都會重渲染子組件。

在學(xué)會使用React Hooks之前,可以先看一下相關(guān)原理學(xué)習(xí)React Hooks

前言

在 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)于這方面的文章,下面我將通過十個案例來幫助你認(rèn)識理解并可以熟練運(yùn)用 React Hooks 大部分特性。

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

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

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}
); } }

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

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

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

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

useEffect 處理副作用

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

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}
); } }

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

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

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);
    // 一定注意下這個順序:
    // 告訴react在下次重新渲染組件之后,同時是下次執(zhí)行上面setInterval之前調(diào)用
    return () => {
      document.title = "componentWillUnmount";
      clearInterval(timer);
    };
  }, []);
  return (
    
Count: {count}
); }

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

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

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

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

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

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

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

useContext 減少組件層級

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

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)行改造。在線 Demo

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)且不會增加組件樹深度。

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

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

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}
      
      
    
  );
}

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

useCallback 記憶函數(shù)

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

class App {
    render() {
        return 
{ console.log("do something"); }} />
; } }

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

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

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

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

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

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

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

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

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

useMemo 記憶組件

useCallback 的功能完全可以由 useMemo 所取代,如果你想通過使用 useMemo 返回一個記憶函數(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ù)都不會發(fā)生改變
  return Click Me;
}

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

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

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 改變時,child1/child2 才會重新渲染。從例子可以看出來,只有在第二個參數(shù)數(shù)組的值發(fā)生變化時,才會觸發(fā)子組件的更新。

useRef 保存引用值

useRef 跟 createRef 類似,都可以用來生成對 DOM 對象的引用,看個簡單的例子:在線 Demo

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

{name}

); }

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 的特性。可以認(rèn)為 ref 在所有 Render 過程中保持著唯一引用,因此所有對 ref 的賦值或取值,拿到的都只有一個最終狀態(tài),而不會在每個 Render 間存在隔離。參考例子:精讀《Function VS Class 組件》

React Hooks 中存在 Capture Value 的特性:在線 Demo

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

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

  return (
    

You clicked {count} times

); }

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

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

); }

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

useImperativeHandle 透傳 Ref

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

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)。

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

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

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 會在 render,DOM 更新之后同步觸發(fā)函數(shù),會優(yōu)于 useEffect 異步觸發(fā)函數(shù)。

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

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

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

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

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

不過useLayoutEffect在服務(wù)端渲染時會出現(xiàn)一個warning,要消除的話得用useEffect代替或者推遲渲染時機(jī)。見說明和討論。

React Hooks 不足

盡管我們通過上面的例子看到 React Hooks 的強(qiáng)大之處,似乎類組件完全都可以使用 React Hooks 重寫。但是當(dāng)下 v16.8 的版本中,還無法實(shí)現(xiàn) getSnapshotBeforeUpdate 和 componentDidCatch 這兩個在類組件中的生命周期函數(shù)。官方也計劃在不久的將來在 React Hooks 進(jìn)行實(shí)現(xiàn)。

原文地址

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/6994.html

相關(guān)文章

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

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

    Lin_YT 評論0 收藏0
  • react hooks 全面轉(zhuǎn)換攻略(一) react本篇之useState,useEffect

    摘要:經(jīng)典案例此例子中是最新的語法其中是他的值是用來設(shè)置值的函數(shù)是初始值該初始值可以接受任何參數(shù)但是記得當(dāng)他接受為一個函數(shù)時就變成了延遲初始化該函數(shù)返回值即為這兩種初始化方式是相等的但是在函數(shù)為初始值時會被執(zhí)行一次這里只會在初始化的時候執(zhí)行中的 useState 經(jīng)典案例: import { useState } from react; function Example() { con...

    KnewOne 評論0 收藏0
  • 10分鐘了解 react 引入的 Hooks

    摘要:最近官方在大會上宣布內(nèi)測將引入。所以我們有必要了解,以及由此引發(fā)的疑問。在進(jìn)一步了解之前,我們需要先快速的了解一些基本的的用法。如何解決狀態(tài)有關(guān)的邏輯的重用和共享問題。 showImg(https://segmentfault.com/img/remote/1460000016886798?w=1500&h=750); 大家好,我是谷阿莫,今天要將的是一個...,哈哈哈,看到這個題我就...

    Lucky_Boy 評論0 收藏0
  • React Hooks實(shí)現(xiàn)異步請求實(shí)例—useReducer、useContext和useEffec

    摘要:本文是學(xué)習(xí)了年新鮮出爐的提案之后,針對異步請求數(shù)據(jù)寫的一個案例。注意,本文假設(shè)了你已經(jīng)初步了解的含義了,如果不了解還請移步官方文檔。但不要忘記和上下文對象可以看做是寫法的以及三個鉤子函數(shù)的組合。 本文是學(xué)習(xí)了2018年新鮮出爐的React Hooks提案之后,針對異步請求數(shù)據(jù)寫的一個案例。注意,本文假設(shè)了:1.你已經(jīng)初步了解hooks的含義了,如果不了解還請移步官方文檔。(其實(shí)有過翻譯...

    Code4App 評論0 收藏0

發(fā)表評論

0條評論

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