介紹 於react 16.8版本引入,主要功能在於讓你無需建立一個類定義,便可使用
state
等react特性。
Hook 是一些可讓你在==函數組件==裏「鉤入」 React state 及生命週期等特性的函數。Hook 不能在 class 組件中使用 —— 這使得你不使用 class 也能使用 React。html
邏輯代碼難以在組件間複用react
render propsnpm
非class模式下,使用更多的react特性編程
沒有破壞性改動數組
useState:< S >(initialState: S | (() => S))=> [S, Dispatch<SetStateAction< S >>];瀏覽器
useState
的組件,獲取的數據並非同一個,全部 state 和反作用都是徹底隔離的。Dispatch<SetStateAction< S >>
會觸發函數組件的從新渲染。useEffect:(effect: ()=>?()=>void, deps?: DependencyList)=> void;緩存
effect
返回的清潔函數(若是有)來取消反作用(好比訂閱,計時器等)deps
標識effect所依賴的值數組。若爲空數組[],則僅在第一次渲染後調用,並在卸載前銷燬。(此時更相似componentDidMount
和 componentWillUnmount
)每次渲染後調用,==包括==第一次(React類生命週期中,componentDidMount
與 componentDidUpdate
的合集)性能優化
componentDidMount() { ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } componentWillUnmount() { ChatAPI.unsubscribeFromFriendStatus( this.props.friend.id, this.handleStatusChange ); } //假如在在組件展現在屏幕上時,friend.id變化了。此時組件沒有正常取消原來的訂閱邏輯,同時在取消訂閱時傳遞了錯誤的好友id,可能致使一些bug
//需添加 componentDidUpdate 來解決這個問題 componentDidUpdate(prevProps) { if(prevPropsfriend.id !== this.props.friend.id){ // 取消訂閱以前的 friend.id ChatAPI.unsubscribeFromFriendStatus( prevProps.friend.id, this.handleStatusChange ); // 訂閱新的 friend.id ChatAPI.subscribeToFriendStatus( this.props.friend.id, this.handleStatusChange ); } }
function FriendStatus(props) { // ... useEffect(() => { // ... ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange); return () => { ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange); }; },[props.friend.id]);//僅在friend.id改變時更新
傳遞給 useEffect 的函數在每次渲染中都會有所不一樣,這是刻意爲之的。事實上這正是咱們能夠在 effect 中獲取最新的的值,而不用擔憂其過時的緣由。每次咱們從新渲染,都會生成新的 effect,替換掉以前的。某種意義上講,effect 更像是渲染結果的一部分 —— 每一個 effect 「屬於」一次特定的渲染。閉包
effect
useEffect會在每次瀏覽器繪製後,且下一次繪製前執行函數式編程
useMemo<T>(factory: () => T, deps: DependencyList | undefined)=> T;
deps
數組內依賴項改變時計算memoized useMemo
的函數會在渲染期間執行,可用於緩存子節點的渲染結果。const Button = React.memo((props) => { // 你的組件 });
useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T;
function MyComponent(props) { const clickCallback = React.useCallback(() => { // ... }, []); // 這裏若是直接傳遞匿名函數,會形成每次渲染結果與上一次不一致 // 在這個例子中:MyComponent會從新渲染,但button不會 return <button onClick={clickCallback}>Click Me!</button>; }
useRef<T>(initialValue: T)=> MutableRefObject<T>;
useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化爲傳入的參數(initialValue)
useRef
實現了一套穿透閉包的邏輯。<div ref={myRef} />
形式傳入組件,則不管該節點如何改變,React 都會將 ref 對象的 .current 屬性設置爲相應的 DOM 節點。function TextInputWithFocusButton() { const inputEl = useRef(null); const onButtonClick = () => { // `current` 指向已掛載到 DOM 上的文本輸入元素 inputEl.current.focus(); }; return ( <> <input ref={inputEl} type="text" /> <button onClick={onButtonClick}>Focus the input</button> </> ); }
props
或者state
(prePorps
及preState
)。function Counter() { const [count, setCount] = useState(0); const prevCountRef = useRef(); useEffect(() => { prevCountRef.current = count; }); const prevCount = prevCountRef.current; return <h1>Now: {count}, before: {prevCount}</h1>; } // 或者使用自定義hook function Counter() { const [count, setCount] = useState(0); const prevCount = usePrevious(count); return <h1>Now: {count}, before: {prevCount}</h1>; } function usePrevious(value) { const ref = useRef(); useEffect(() => { ref.current = value; }); return ref.current; }
React依賴Hook調用的順序來確保state
與useState
的對應關係。
按照官方描述,這個是 自定義Hook
自定義 Hook 是一個函數,其名稱必須以「use」 開頭,函數內部能夠調用其餘的 Hook。
import React, { useState, useEffect } from 'react'; function useFriendStatus(friendID) { const [isOnline, setIsOnline] = useState(null); useEffect(() => { function handleStatusChange(status) { setIsOnline(status.isOnline); } 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 ( <li style={{ color: isOnline ? 'green' : 'black' }}> {props.friend.name} </li> ); }
useCallback
與useMemo
主要用於性能優化,不要過早進行性能優化。不然沒法比較優化結果,極可能某個不注意的角落反而會致使性能下降。與 class 組件中的 setState
方法不一樣,useState
不會自動合併更新對象。你能夠用函數式的 setState
結合展開運算符來達到合併更新對象的效果。
setState(prevState => { // 也可使用 Object.assign return {...prevState, ...updatedValues}; });