摘要:可以在不改變組件層級的前提下將帶有狀態的邏輯抽離出來。因此在中增加了一個特性,允許傳入的函數再返回一個函數,這個返回函數的執行時機是下一次觸發這個前,以及組件卸載前。當第二個參數為空數組時,返回函數進行清理工作只會在組件卸載時執行。
hooks是什么
hooks是react16.8版本中新增的特性,它讓我們能夠在不寫class的情況下使用狀態和其他react特性。也就是說現在我們可以在函數組件中進行狀態管理了。
hooks解決了什么問題組件中帶狀態的邏輯很難復用
在hooks之前解決這個問題的手段是render props和高階組件。但是這些方法都需要我們去修改組件層級關系,讓代碼變得很繁瑣。
hooks可以在不改變組件層級的前提下將帶有狀態的邏輯抽離出來。
復雜組件讓人難以理解
原先用class寫的組件集成了許多生命周期函數,這些生命周期函數中又包含了許多互不相關的邏輯,比如接口請求,事件綁定等等。這導致組件邏輯復雜之后難以理解也難以測試。
hooks可以將復雜組件的邏輯拆分成更小的函數,這些函數只負責單一的邏輯。拆分后的優點是易懂易測試。
class本身存在的問題
盡管class已經是一個語法糖了,但是react的開發者認為this是一個很麻煩的東西,我們在用class寫組件前必須先搞清楚this的工作原理。另外class組件在react編譯過程中也存在一些問題,如壓縮率并不是很好,熱加載不穩定等等。
hooks可以讓我們在函數組件中管理狀態。盡管完全拋棄class組件還為時尚早,但是有了hooks我們使用class組件的機會將越來越少。
基本用法:
import React, { useState } from "react"; export default function Foo() { const [selectedKey, setSelectedKey] = useState(""); const someHandler = () => { setSelectedKey("1") }; ... return ...; }
上面例子中,useState函數會返回一個數組,數組第一項是我們定義的一個狀態selectedKey,第二項是修改這個狀態的函數,而userState接收的參數就是這個狀態的初始值。當我們使用setSelectedKey修改狀態時,react會重新渲染該組件,效果跟setState一樣。
這段代碼改成class的寫法是這樣的:
import React, { Component } from "react"; export default class Foo extends Component { state = { selectedKey: "" } someHandler = () => { this.setState({selectedKey: "1"}); } ... render() { return ...; } }
區別:
使用class時,我們把組件的所有狀態都放在state這個對象中;而一個useState只定義一個狀態量,組件有幾個狀態變量就寫幾行useState
setState是將新狀態merge到老狀態中,而useState返回的函數setSelectedKey是將新狀態替換老狀態,因為一個useState只定義一個狀態量所以這邊直接替換是沒有問題的
useEffect顧名思義,useEffect就是去做一些有副作用的事。默認情況下useEffect接收一個函數作為參數,在每次render結束后react會去執行這個函數,效果相當于componentDidMount和componentDidUpdate的組合。
下面這段代碼表示每次渲染后將狀態selectedKey的值設為home:
import React, { useState, useEffect } from "react"; export default function Foo() { const [selectedKey, setSelectedKey] = useState(""); useEffect(()=> { setSelectedKey("home"); }); ... return ...; }
useEffect的功能還不止這么簡單,當我們進行某些副作用操作后,往往需要在組件卸載前做一些清理工作,比如清除定時器,解綁事件監聽器等等。因此react在useEffect中增加了一個特性,允許傳入的函數再返回一個函數,這個返回函數的執行時機是下一次觸發這個useEffect前,以及組件卸載前。
如果我們只想在組件卸載前進行一些清理工作,那就要用到uesEffect的第二個參數了。第二個參數是一個數組,里面可以放這個副作用的依賴,作用是控制這個副作用執行的時機,只有當依賴發生變化的時候才會執行這個副作用。當第二個參數為空數組時,返回函數(進行清理工作)只會在組件卸載時執行。
下面這個例子的作用是在組件首次渲染后以及props.source的值發生變化后執行subscribe( ),在下一次執行subscribe( )前以及組件卸載前執行unsubscribe( ):
useEffect( () => { const subscription = props.source.subscribe(); return () => { subscription.unsubscribe(); }; }, [props.source] );
使用useEffect可以模擬react的某些生命周期函數
useEffect(() => { // 這里在mount時執行一次 }, []);
useEffect(() => { // 這里在mount時執行一次 return () => { // 這里在unmount時執行一次 } }, []);
// useRef會返回一個對象,這個對象有個current屬性,值為傳給useRef的參數 // useRef在組件生命周期中只初始化一次,之后它會幫我們保存返回的對象 const mounting = useRef(true); useEffect(() => { if (mounting.current) { mounting.current = false; // 對current的修改會被useRef保存,但修改不會引起重新渲染 } else { // 這里只在update時執行 } });舉例
需求:使用antd的menu組件實現一個側邊欄,類似下面的樣子,當用戶輸入不同url時側邊欄需要聯動
實現:
import React, { useState, useEffect } from "react"; import { Menu } from "antd"; export default function Sider() { const [selectedKey, setSelectedKey] = useState(""); const [openKeys, setOpenKeys] = useState([]); // 組件更新時根據url更新選中的菜單項 useEffect(() => { const key = getSelectedKey(); // 根據url得到選中的菜單項 setSelectedKey(key); }); // 組件mount時根據url自動展開子菜單 useEffect(() => { const key = getOpenKey(); // 根據url得到應該展開的菜單 setOpenKeys([key]); }, []); ... return ( ); }
分析:
組件使用useState定義了兩個狀態量:selectedKey和openKeys;
第一個useEffect用于更新selectedKey,它會在每次render后從url中獲取當前選中的菜單項,然后更新selectedKey;
第二個useEffect用于首次進入網站時,從url中獲取應該展開的菜單并更新openKeys,它只在組件創建時執行,相當于componentDidMount;
當用戶點擊父菜單想要展開或收起時,通過onOpenChange事件來觸發openKeys的更新;
當用戶點擊子菜單想要選中時,會先觸發路由跳轉(這個邏輯無法從代碼中獲取,請自行腦補),路由改變會引發改組件重新渲染,繼而觸發第一個useEffect來更新selectedKey。
自定義hooks文章開頭已經講到了hooks可以很方便的實現帶狀態的邏輯復用。
下面是一個簡單的自定義hooks,功能是請求接口并返回數據:
import { useState, useEffect } from "react"; export default function useUserInfo() { const [userInfo, setUserInfo] = useState(null); useEffect(() => { fetch("https://react.hooks.com/api/userinfo").then( data => { setUserInfo(data); }, ); }, []); return userInfo; }
使用也很簡單,當Home組件加載時會通過useUserInfo這個自定義hooks去請求接口,接口數據返回時Home組件會自動更新:
import React from "react"; import useUserInfo from "../../hooks/useUserInfo"; export default function Home() { const userInfo = useUserInfo(); returnhooks + context進行全局狀態管理{userInfo}; }
react提供了useContext這個hooks使得在函數組件中使用context變得更加方便。
如果項目沒有復雜到需要上redux,可以使用下面的方法進行全局狀態管理。
首先創建一個context:
// globalContext.js import React from "react"; export default React.createContext({ musicianPlan: "1", language: "zh", changeMusicianPlan: () => {}, changeLanguage: () => {}, });
然后定義一個高階組件,用于管理context中的狀態:
// globalState.jsx import React, { useState } from "react"; import GlobalContext from "./globalContext"; export default function GlobalState(props) { const [musicianPlan, setMusicianPlan] = useState("1"); const [language, setLanguage] = useState("zh"); const changeMusicianPlan = planId => { setMusicianPlan(planId); }; const changeLanguage = lang => { setLanguage(lang); }; return ({props.children} ); }
將這個高階組件放到組件樹的頂層:
// app.jsx import React from "react"; import GlobalState from "./context/globalState"; export default function App() { return (); } ...
在Header組件中用useContext這個hooks獲取到context,然后調用changeMusicianPlan方法來改變全局狀態musicianPlan:
import React, { useContext, ReactElement } from "react"; import { Select } from "antd"; import GlobalContext from "../../context/globalContext"; const Option = Select.Option; export default function Header() { const globalContext = useContext(GlobalContext); return ( ); }
在Home組件中同樣使用useContext獲取context,然后使用全局狀態musicianPlan進行動態渲染:
import React, { useContext } from "react"; import GlobalContext from "../../context/globalContext"; export default function Home() { const globalContext = useContext(GlobalContext); return{globalContext.musicianPlan}; }
當然上面的方法也可以用于某個局部組件樹的狀態管理,將狀態進行拆分管理不僅提高運行效率也更清晰易懂。
使用hooks的注意事項hooks只能在組件內部的最頂層調用,不能將其放在循環語句、條件語句或者子函數內;
hooks只能在函數組件或自定義hooks中使用;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103726.html
摘要:前言的基本概念組件的構建方法以及高級用法這背后的一切如何運轉深入內部的實現機制和原理初探源碼代碼組織結構包含一系列的工具方法插件包含一系列同構方法包含一些公用或常用方法如等包含一些測試方法等包含一些邊界錯誤的測試用例是代碼的核心部分它包含了 前言 React的基本概念,API,組件的構建方法以及高級用法,這背后的一切如何運轉,深入Virtual DOM內部的實現機制和原理. 初探Rea...
摘要:它的作用就是像它的名字那樣,建立一個從外部的對象到組件的對象的映射關系。比如表示從整個的表示當前組件容器的用來建立組件的參數到方法的映射比如表示它定義了哪些用戶的操作應該當作,傳給。 最近做的項目加入了react-redux,對react-redux一直沒理解透徹,最近有時間把react-redux梳理了一番,希望能夠幫助到大家, 首先有這幾個文件,action,reducer,sag...
摘要:相信用的同學也不少找到函數在其中中添加啟用編譯。。。react 最近已經開始使用react技術棧了,從頭開始搭建項目,有必要的記錄一下配置的過程以及項目分層的思路,這次后臺項目采用的主要采用react-create-app腳手架以及Ant DesignUI 以及多語言react-intl create-react-app 這是官方維護的腳手架應用 我們一般也采用這個 $ npm or c...
閱讀 2164·2021-11-11 16:55
閱讀 1685·2019-08-30 15:54
閱讀 2817·2019-08-30 15:53
閱讀 2211·2019-08-30 15:44
閱讀 1152·2019-08-30 15:43
閱讀 965·2019-08-30 11:22
閱讀 1942·2019-08-29 17:20
閱讀 1566·2019-08-29 16:56