欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

在?React?項(xiàng)目中全量使用?Hooks的方法

 更新時(shí)間:2022年10月11日 09:33:37   作者:清風(fēng)無(wú)影Q  
這篇文章主要介紹了在?React?項(xiàng)目中全量使用?Hooks,使用 Hooks 能為開(kāi)發(fā)提升不少效率,但并不代表就要拋棄 Class Component,依舊還有很多場(chǎng)景我們還得用到它,本文給大家介紹的非常詳細(xì),需要的朋友可以參考下

前言

此篇文章整理了在 React 項(xiàng)目開(kāi)發(fā)中常用的一些 Hooks

React Hooks

Hooks 只能用于函數(shù)組件當(dāng)中

useState

import { useState } from 'react';

const Component = () => {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>click</button>
  )
}

此方法會(huì)返回兩個(gè)值:當(dāng)期狀態(tài)和更新?tīng)顟B(tài)的函數(shù)。效果同 this.state this.setState,區(qū)別是 useState 傳入的值并不一定要對(duì)象,并且在更新的時(shí)候不會(huì)把當(dāng)前的 state 與舊的 state 合并。

useReducer

useReducer 接收兩個(gè)參數(shù),第一個(gè)是 reducer 函數(shù),通過(guò)該函數(shù)可以更新 state,第二個(gè)參數(shù)為 state 的初始值,是 useReducer 返回的數(shù)組的第一個(gè)值,也是在 reducer 函數(shù)第一次被調(diào)用時(shí)傳入的一個(gè)參數(shù)。

基礎(chǔ)用法

import { useState } from 'react';

const Component = () => {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>click</button>
  )
}

在基礎(chǔ)用法中,返回一個(gè) dispatch 通過(guò) dispatch 觸發(fā)不同的 action 來(lái)加減 state。這里既然能傳string action 那么肯定也能傳遞更復(fù)雜的參數(shù)來(lái)面對(duì)更復(fù)雜的場(chǎng)景。

進(jìn)階用法

import { useReducer } from 'react';

const Component = () => {
  const [userInfo, dispatch] = useReducer(
    (state, { type, payload }) => {
      switch (type) {
        case 'setName':
          return {
            ...state,
            name: payload
          };
        case 'setAge':
          return {
            ...state,
            age: payload
          };
      }
    },
    {
      name: 'Jace',
      age: 18
    }
  );

  return (
    <button onClick={() => dispatch({ type: 'setName', payload: 'John' })}>
      click
    </button>
  );
};

useContext

在上述案例 useReducer 中,我們將函數(shù)的參數(shù)改為一個(gè)對(duì)象,分別有typepayload 兩個(gè)參數(shù),type 用來(lái)決定更新什么數(shù)據(jù),payload 則是更新的數(shù)據(jù)。寫過(guò) react-redux 的同學(xué)可能發(fā)這個(gè) reducer 與 react-redux 中的 reducer 很像,我們借助 react-redux 的思想可以實(shí)現(xiàn)一個(gè)對(duì)象部分更改的 reducer ,那么我們便可以使用 React Hooks 的 useContext 來(lái)實(shí)現(xiàn)一個(gè)狀態(tài)管理。

import { useMemo, createContext, useContext, useReducer } from 'react';

const store = createContext([]);

const App = () => {
  const reducerValue = useReducer(
    (state, { type, payload }) => {
      switch (type) {
        case 'setName':
          return {
            ...state,
            name: payload
          };
        case 'setAge':
          return {
            ...state,
            age: payload
          };
      }
    },
    {
      name: 'Jace',
      age: 18
    }
  );
  const [state, dispatch] = reducerValue;
  
  const storeValue = useMemo(() => reducerValue, reducerValue);
  
  return (
    <store.Provider value={storeValue}>
      <Child />
    </store.Provider>
  );
};

const Child = () => {
  const [state, dispatch] = useContext(store); // 在子組件中使用
  console.log(state);
  return (
    <button onClick={() => dispatch({ type: 'setName', payload: 'John' })}>
      click
    </button>
  );
}

useEffect

import { useState, useEffect } from 'react';

let timer = null;

const Component = () => {
  const [count, setCount] = useState(0);
  
  // 類似于 class 組件的 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    document.title = `You clicked ${count} times`;
    
    timer = setInterval(() => {
      // events ...
    }, 1000)
    
    return () => {
      // 類似 componentWillUnmount
      // unmount events ...
      clearInterval(timer); // 組件卸載、useEffect 更新 移除計(jì)時(shí)器
    };
  }, [count]);
  
  // ...
}

如果 useEffect 第二個(gè)參數(shù)數(shù)組內(nèi)的值發(fā)生了變化,那么useEffect第一個(gè)參數(shù)的回調(diào)將會(huì)被再執(zhí)行一遍,這里要注意的useEffect 的返回值函數(shù)并不只是再組件卸載的時(shí)候執(zhí)行,而是在這個(gè) useEffect 被更新的時(shí)候也會(huì)調(diào)用,例如上述 count 發(fā)生變化后,useEffect 返回的方法也會(huì)被執(zhí)行,具體原因見(jiàn)Using the Effect Hook – React (reactjs.org)

useLayoutEffect

useLayoutEffect useEffect 的API相同,區(qū)別:useEffect 在瀏覽器渲染后執(zhí)行,useLayoutEffect 在瀏覽器渲染之前執(zhí)行,由于JS是單線程,所以 useLayoutEffect 還會(huì)阻塞瀏覽器的渲染。區(qū)別就是這,那么應(yīng)用場(chǎng)景肯定是從區(qū)別中得到的,useLayoutEffect 在渲染前執(zhí)行,也就是說(shuō)我們?nèi)绻袪顟B(tài)變了需要依據(jù)該狀態(tài)來(lái)操作DOM,為了避免狀態(tài)變化導(dǎo)致組件渲染,然后更新 DOM 后又渲染,給用戶肉眼能看到的閃爍,我們可以在這種情況下使用 useLayoutEffect。

當(dāng)然這個(gè)不只是狀態(tài)的改變,在任何導(dǎo)致組件重新渲染,而且又要改變 DOM 的情況下都是 useLayoutEffect 的使用場(chǎng)景。當(dāng)然這種場(chǎng)景不多,useLayoutEffect 也不能多用,且使用時(shí)同步操作時(shí)長(zhǎng)不能過(guò)長(zhǎng),不然會(huì)給用戶帶來(lái)明顯的卡頓。

useRef

細(xì)心的同學(xué)有可能發(fā)現(xiàn)我在上面寫 useEffect 中有一個(gè) timer 變量,我將其定義在了函數(shù)組件外面,這樣寫簡(jiǎn)單使用是沒(méi)問(wèn)題的,但是如果該組件在同一頁(yè)面有多個(gè)實(shí)例,那么組件外部的這個(gè)變量將會(huì)成共用的,會(huì)帶來(lái)一個(gè)沖突,所以我們需要一個(gè)能在函數(shù)組件聲明周期內(nèi)部的變量,可以使用 useState 中的 state 但是 state 發(fā)生變化組件也會(huì)隨之刷新,在有些情況是不需要刷新的,只是想單純的存一個(gè)值,例如計(jì)時(shí)器的 timer 以及子組件的 Ref 實(shí)例等等。

import React, { useRef, useState, useEffect } from 'react';

const Compnent = () => {
  const timer = useRef(null);
  const [count, setCount] = useState(0);

  useEffect(() => {
    clearInterval(timer.current);
    timer.current = setTimeout(() => {
      setCount(count + 1);
    }, 1000);
  }, [count]);

  return <div>UseRef count: {count}</div>;
}

useRef 只接受一個(gè)參數(shù),就是 初始值,之后可以通過(guò)賦值 ref.current 來(lái)更改,我們可以將一些不影響組件聲明周期的參數(shù)放在 ref 中,還可以將 ref 直接傳遞給子組件 子元素。

const ref = useRef();

<div ref={ref}>Hello</div>
// or
<Child ref={ref} />

或許有同學(xué)這時(shí)候會(huì)想到,當(dāng)子組件為 Class 組件時(shí),ref 獲取的是 Class 組件的實(shí)例,上面包含 Class 的所有方法屬性等。但當(dāng)子組件為 Function 組件時(shí),ref 能拿到什么,總不可能是 function 內(nèi)定義的方法、變量。

useImperativeHandle

import React, { useRef, useState, useImperativeHandle } from 'react';

const App = () => {
  const ref = useRef();
  return (
      <Child ref={ref} />
  );
};

const Child = React.forwardRef((props, ref) => {
  const inputRef = useRef();
  const [value, setValue] = useState(1);
  
  useImperativeHandle(ref, () => ({
    value, // 內(nèi)部變量
    setValue, // 方法
    input: inputRef.current // Ref
  }));
  
  return (
    <input value={value} inputRef={inputRef} />
  );
})

使用 useImperativeHandle 鉤子可以自定義將子組件中任何的變量,掛載到 ref 上。React.forwardRef 方法可以讓組件能接收到 ref ,然后再使用或者透?jìng)鞯礁聦印?/p>

useCallback

import React, { useCallback } from 'react';

const Component = () => {
  const setUserInfo = payload => {}; // request api

  const updateUserInfo = useCallback(payload => {
    setUserInfo(Object.assign({}, userInfo, payload));
  }, [userInfo]);
  
  return (
    <UserCard updateUserInfo={updateUserInfo}/>
  )
}

useCallback 會(huì)在二個(gè)參數(shù)的依賴項(xiàng)發(fā)生改變后才重新更新,如果將此函數(shù)傳遞到子組件時(shí),每次父組件渲染此函數(shù)更新,就會(huì)導(dǎo)致子組件也重新渲染,可以通過(guò)傳遞第二個(gè)參數(shù)以避免一些非必要性的渲染。

useMemo

import React, { useMemo } from 'react';

const Component = () => {
  const [count, setCount] = useState(0);
 
  const sum = useMemo(() => {
    // 求和邏輯
    return sum;
  }, [count]);
  
  return <div>{sum}</div>
}

useMemo 的用法跟 useCallback 一樣,區(qū)別就是一個(gè)返回的是緩存的方法,一個(gè)返回的是緩存的值。上述如果依賴值 count 不發(fā)生變化,計(jì)算 sum 的邏輯也就只會(huì)執(zhí)行一次,從而性能。

React Redux Hooks useSelector

import { shallowEqual, useSelector } from 'react-redux';

const Component = () => {
  const userInfo = useSelector(state => state.userInfo, shallowEqual);
  
  // ...
}

useSelector 的第二個(gè)參數(shù)是一個(gè)比較函數(shù),useSelector 中默認(rèn)使用的是 === 來(lái)判斷兩次計(jì)算的結(jié)果是否相同,如果我們返回的是一個(gè)對(duì)象,那么在 useSelector 中每次調(diào)用都會(huì)返回一個(gè)新對(duì)象,所以所以為了減少一些沒(méi)必要的 re-render,我們可以使用一些比較函數(shù),如 react-redux 自帶的 shallowEqual,或者是 Lodash 的 _.isEqual()、Immutable 的比較功能。

useDispatch

import React, { useCallback } from 'react';
import { useDispatch } from 'react-redux';

const Compnent = () => {
  const dispatch = useDispatch();
  const clearUserInfo = useCallback(
    () => dispatch({ type: 'clearUserInfo' }),
    [dispatch]
  );
  
  return (
    <button onClick={clearUserInfo}>click</buttn>
  )
}

使用 dispatch 來(lái)調(diào)度操作,加上useCallback來(lái)減少不必要的渲染。

React Router Hooks

useHistory

import { useHistory } from 'react-router';

const Compnent = () => {
  const history = useHistory();
  
  return (
    <button onClick={() => history.push('/home')}>go home</buttn>
  )
}

useLocation

import React, { useEffect } from 'react';
import { useLocation } from 'react-router';

const Compnent = () => {
  const location = useLocation();
  
  useEffect(() => {
    // ...
  }, [location])
}

URL一發(fā)生變化,將返回新的 location ,一般可以用來(lái)監(jiān)聽(tīng) location.search

useParams

import { useParams, useEffect } from 'react-router';

const Component = () => {
  const params = useParams();
  
  const getUserInfo = id => { // request api
    // some event
  };
  useEffect(() => {
    // parms 的 uid 發(fā)生變化就會(huì)重新請(qǐng)求用戶信息
    getUserInfo(params.uid);
  }, [params.uid]);
  
  // ...
}

useParams 返回 react-router 的參數(shù)鍵值對(duì)

useRouteMatch

import { useRouteMatch } from 'react-router';

const Component = () => {
  const match = useRouteMatch('/login');
  
  // ...
}

useRouteMatch 可以傳入一個(gè)參數(shù) path,不傳參數(shù)則返回當(dāng)前路由的參數(shù)信息,如果傳了參數(shù)則用來(lái)判斷當(dāng)前路由是否能匹配上傳遞的 path,適用于判斷一些全局性組件在不同路由下差異化的展示。

參考

React Hooks

React Redux Hooks

React Router Hooks

結(jié)語(yǔ)

使用 Hooks 能為開(kāi)發(fā)提升不少效率,但并不代表就要拋棄 Class Component,依舊還有很多場(chǎng)景我們還得用到它,比如需要封裝一個(gè)公共的可繼承的組件,當(dāng)然通過(guò)自定義 hooks 也能將一些共用的邏輯進(jìn)行封裝,以便再多個(gè)組件內(nèi)共用。

下期更新在React 中自定義 Hooks 的應(yīng)用場(chǎng)景 ,主要講一些 Hooks 的高階應(yīng)用

到此這篇關(guān)于在 React 項(xiàng)目中全量使用 Hooks的文章就介紹到這了,更多相關(guān)React使用 Hooks內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • react-native-video實(shí)現(xiàn)視頻全屏播放的方法

    react-native-video實(shí)現(xiàn)視頻全屏播放的方法

    這篇文章主要介紹了react-native-video實(shí)現(xiàn)視頻全屏播放的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • create-react-app構(gòu)建項(xiàng)目慢的解決方法

    create-react-app構(gòu)建項(xiàng)目慢的解決方法

    這篇文章主要介紹了create-react-app構(gòu)建項(xiàng)目慢的解決方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-03-03
  • React從命令式編程到聲明式編程的原理解析

    React從命令式編程到聲明式編程的原理解析

    這篇文章主要介紹了React從命令式編程到聲明式編程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-09-09
  • 使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼

    使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼

    這篇文章主要介紹了使用react render props實(shí)現(xiàn)倒計(jì)時(shí)的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • 淺談React的React.FC與React.Component的使用

    淺談React的React.FC與React.Component的使用

    本文主要介紹了React的React.FC與React.Component的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 原生實(shí)現(xiàn)一個(gè)react-redux的代碼示例

    原生實(shí)現(xiàn)一個(gè)react-redux的代碼示例

    這篇文章主要介紹了原生實(shí)現(xiàn)一個(gè)react-redux的代碼示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • react hooks入門詳細(xì)教程

    react hooks入門詳細(xì)教程

    這篇文章主要介紹了react hooks入門詳細(xì)教程,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • 使用React制作一個(gè)貪吃蛇游戲的代碼詳解

    使用React制作一個(gè)貪吃蛇游戲的代碼詳解

    Snake?Game?使用?ReactJS?項(xiàng)目實(shí)現(xiàn)功能組件并相應(yīng)地管理狀態(tài),開(kāi)發(fā)的游戲允許用戶使用箭頭鍵控制蛇或觸摸屏幕上顯示的按鈕來(lái)收集食物并增長(zhǎng)長(zhǎng)度,本文給大家詳細(xì)講解了如何使用?React?制作一個(gè)貪吃蛇游戲,需要的朋友可以參考下
    2023-11-11
  • React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼

    React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼

    這篇文章主要介紹了React 使用recharts實(shí)現(xiàn)散點(diǎn)地圖的示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-12-12
  • React獲取input值并提交的2種方法實(shí)例

    React獲取input值并提交的2種方法實(shí)例

    這篇文章主要給大家介紹了關(guān)于React獲取input值并提交的2種方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04

最新評(píng)論