react hook小記

useState

const [state, setState] = useState(initialState);

useState 返回的第一個(gè)值將始終是更新后最新的 state偷线,并且與 class 組件中的 setState 方法不同斯入,useState 不會(huì)自己合并更新對(duì)象脖含。但是可以通過用函數(shù)式的 setState 結(jié)合展開運(yùn)算符來達(dá)到合并更新對(duì)象的效果劳坑。效果如下

setState(prevState => {
  //  Object.assign 也可以實(shí)現(xiàn)這種效果 
  return {...prevState, ...updatedValues};
});

useEffect

  • 1
    useEffect 用來完成副作用操作铺厨。賦值給 useEffect 的函數(shù)會(huì)在組件渲染到屏幕之后執(zhí)行(延遲執(zhí)行)
  • 2
    useEffect 傳遞的第二個(gè)參數(shù)偏竟,用來控制useEffect的執(zhí)行時(shí)機(jī)窍株,是一個(gè)數(shù)組民轴。傳入空數(shù)組 表示只更新一次相當(dāng)與classcomponentDidMount 只會(huì)執(zhí)行一次。
  • 3
    受同一種數(shù)值影響影響的放在同一塊 例如
function Example({ someProp }) {
  useEffect(() => {
    function doSomething() {
      console.log(someProp);
    }

    doSomething();
  }, [someProp]); 
}

或者訂閱和消除 放在一起

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // 清除訂閱
    subscription.unsubscribe();
  };
});

這樣可以控制重復(fù)訂閱以及 解決沒有必要調(diào)用 球订。

  • 3
    componentDidMount后裸、componentDidUpdate 不同,useEffect 的函數(shù)會(huì)在完成布局與繪制后冒滩,被延遲調(diào)用微驶。(所以這使得他適用于很多常見你的副作用場(chǎng)景)。然而,并非所有 effect 都需要被延遲執(zhí)行因苹。例如苟耻,一個(gè)對(duì)用戶可見的 DOM 變更就必須在瀏覽器執(zhí)行下一次繪制前被同步執(zhí)行,這樣用戶才不會(huì)感覺到視覺上的不一致扶檐。(概念上類似于被動(dòng)監(jiān)聽事件和主動(dòng)監(jiān)聽事件的區(qū)別凶杖。)React 為此提供了一個(gè)額外的 useLayoutEffectHook 來處理這類 effect。它和 useEffect 的結(jié)構(gòu)相同款筑,區(qū)別只是調(diào)用時(shí)機(jī)不同官卡。
    雖然 useEffect 會(huì)在瀏覽器繪制后延遲執(zhí)行,但會(huì)保證在任何新的渲染前執(zhí)行醋虏。在開始新的更新前寻咒,React 總會(huì)先清除上一輪渲染的 effect。例子可以參考這里 颈嚼。

useContext

這個(gè)可以獲取共享的value的值

const value = useContext(MyContext);

舉一個(gè)例子 如下

// test-context.js
import React from 'react';
export const TestContext = React.createContext('我是傳過去的值');
//LoginScreen.js
import React, {useState,useEffect,useLayoutEffect} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import BigView from '../Component/BigView';
import {TestContext,themes} from '../Utils/test-context.js';

const LoginScreen = (props) => {
    const [value, setValue] = useState("sdssdsdssdd");
    const onClick = () => {
         setValue((prevState) => {
             if (prevState == '我是傳過去的值') {
                 return '我改變了';
            }
             return '我是傳過去的值';
         });
    }
    return (
        <View style = {{flex:1}}>
            <TestContext.Provider value={value}>
                <BigView/>
            </TestContext.Provider>
        </View>
    );
}

export default LoginScreen;
//BigView.js
import React, {useEffect} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import MiddleView from '../Component/MiddleView';

const BigView =  (props) => {
    useEffect(()=>{
        console.log('BigView useEffect begin ');
    });
    return (
        <View style = {{height:200,backgroundColor:'red'}}>
            <MiddleView/>
        </View>
    );
}

export default React.memo(BigView);
import React, { useEffect,useContext} from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import {TestContext,themes} from '../Utils/test-context.js';

const MiddleView = (props) => {
    useEffect(()=>{
        console.log('MiddleView useEffect begin ');
    });
    let value = useContext(TestContext);
    console.log('value ==============',value);// 這里可以獲取改變的value 的數(shù)值
    return (
        <TestContext.Consumer>
            {(theme) => {
                return (
                    <View style = {{height:100,backgroundColor:'green'}}>
                        <Text>{theme}</Text>
                    </View>
                );
            }}
        </TestContext.Consumer>
    );
}

export default MiddleView;

在上面的例子當(dāng)我改變的時(shí)候 只有 MiddleViewLoginScreen發(fā)生了改變毛秘,如果沒有 使用 React.createContext那么修改 LoginScreen 只會(huì)改變
LoginScreenBigView 不會(huì)重新渲染阻课。這個(gè)以后會(huì)出一個(gè)文章比對(duì)說明一下叫挟。

useEffect

  • 1
    createRef 和 useRef 的作用可以說完全一樣,但是 useRef hook為DOM節(jié)點(diǎn)創(chuàng)建持久引用 限煞,相當(dāng)于this 不會(huì)發(fā)上改變抹恳。也就是說 createRef 每次渲染都會(huì)返回一個(gè)新的引用,而 useRef 每次都會(huì)返回相同的引用署驻。舉一個(gè)例子
import React, {useEffect,useState,useRef,createRef} from 'react';
import { View, Text,Button } from 'react-native';

const BigView =  (props) => {
    const [ index,setIndex ] = useState(0)
    const iAmUseRef = useRef();
    const iAmCreateRef = createRef();

    if (!iAmUseRef.current) {
        iAmUseRef.current = index;
    }
    if (!iAmCreateRef.current) {
        iAmCreateRef.current = index;
    }
    return (
        <View style = {{height:200,backgroundColor:'red'}}>
            
            <Button title = {'add index'} onPress = {() => setIndex(index + 1)}/>
            <Text>{'current index is ', index}</Text>
            <Text>{'useRef.current is ', iAmUseRef.current}</Text>
            <Text>{'createRef.current is', iAmCreateRef.current}</Text>
        </View>
    );
}

export default React.memo(BigView);
效果圖

很明顯 可以看出 useRef 并未發(fā)生改變 奋献,createRef 每次重新render會(huì)重新生成新的引用 會(huì)隨著數(shù)字的變化而變化 。
useRef 相當(dāng)于this createRef 會(huì)隨著變化而變化旺上。

useReducer

  • 1 有一些類似 Redux 瓶蚂。
  • 2 useReducer可以使代碼具有更好的可讀性、可維護(hù)性宣吱、可預(yù)測(cè)性窃这。
  • 3 子組件中直接通過context拿到dispatch,觸發(fā)reducer操作state 子組件征候。對(duì)組件層級(jí)很深的場(chǎng)景特別有用杭攻,不需要一層一層的把 state 和 callback 往下傳
  • 4 惰性初始化
function init(initialCount) {
  return {count: initialCount};
}

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    case 'reset':
      return init(action.payload);
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}>
        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

useCallback 和 useMemo 和 memo

    1. useMemo 計(jì)算結(jié)果是 return 回來的值, 主要用于 緩存計(jì)算結(jié)果的值 ,應(yīng)用場(chǎng)景如: 需要 計(jì)算的狀態(tài) useMemo 可以用來 細(xì)粒度性能優(yōu)化 疤坝。意思也就是說 如果你只希望 組件的 的部分不要進(jìn)行重新渲染兆解,而不是整個(gè) 組件 不要 重新渲染,實(shí)現(xiàn) 局部 Pure 功能卒煞。那么可以按照下面這么用痪宰。
import React, { useMemo } from 'react';

export default (props = {}) => {
    console.log(`--- component re-render ---`);
    return useMemo(() => {
        console.log(`--- useMemo re-render ---`);
        return <div>
            <p>number is : {props.number}</p>
        </div>
    }, [props.number]);
}
    1. useCallback 計(jì)算結(jié)果是 函數(shù), 主要用于 緩存函數(shù),應(yīng)用場(chǎng)景如: 需要緩存的函數(shù),因?yàn)楹瘮?shù)式組件每次任何一個(gè) state 的變化 整個(gè)組件 都會(huì)被重新刷新衣撬,一些函數(shù)是沒有必要被重新刷新的乖订,此時(shí)就應(yīng)該緩存起來,提高性能具练,和減少資源浪費(fèi)乍构。
    1. React.memo 與 PureComponent 很相似,但是是專門給 Function Component 提供的扛点,可以支持指定一個(gè)參數(shù)哥遮,可以相當(dāng)于 shouldComponentUpdate 的作用。有點(diǎn)類似 HOC(高階組件)陵究,在并且內(nèi)部實(shí)現(xiàn) PureComponent + shouldComponentUpdate 的結(jié)合使用眠饮。按照下面的例子來說 isEqual是用來判斷兩次 props 是否有,第二個(gè)參數(shù)不傳遞铜邮,默認(rèn)只會(huì)進(jìn)行 props 的淺比較仪召。 與 class 組件中 shouldComponentUpdate() 方法不同的是,如果 props 相等松蒜,areEqual會(huì)返回 true扔茅;如果 props 不相等,則返回 false秸苗。這與 shouldComponentUpdate 方法的返回值相反召娜。
function SomeComponent(props) {
  /* 組件渲染*/
}
function isEqual(prevProps, nextProps) {
  /*
  這個(gè)方法用來比較前后兩次的 Props 是否發(fā)生變化 需要自己配置 
  */
}
export default React.memo(SomeComponent, isEqual);
    1. 區(qū)別是 useMemo 將調(diào)用 fn 函數(shù)并返回其結(jié)果,而useCallback 將返回 fn 函數(shù)而不調(diào)用它惊楼。React.memo主要針對(duì)組件進(jìn)行 PureComponent優(yōu)化玖瘸。
    1. 下面我舉個(gè)例子
      Class Component中考慮以下的場(chǎng)景:
class BaseComponent extends Component {
  handleClick() {
    console.log('Click happened');
  }
  render() {
    return <Button onPress={() => this.handleClick()}>Click Me</Button>;
  }
}

傳給 Button 的 onPress 方法每次都是重新創(chuàng)建的,這會(huì)導(dǎo)致每次 Foo render 的時(shí)候胁后,Button 也跟著 render店读。優(yōu)化方法有 2 種,箭頭函數(shù)bind攀芯。

同樣的,F(xiàn)unction Component也有這個(gè)問題:

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

  const handleClick() {
    console.log(` click happened ${count}`)
  }
  return <Button onClick={handleClick}>Click Me</Button>;
}

React 給出的方案是useCallback文虏。在依賴不變的情況下 (在我們的例子中是 count )侣诺,它會(huì)返回相同的引用,避免子組件進(jìn)行無意義的重復(fù)渲染:

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

  const memoizedHandleClick = useCallback(
    () => console.log(`Click happened ${count}`), [count],
  ); 
  return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}

useMemo緩存的則是方法的返回值氧秘。使用場(chǎng)景是減少不必要的子組件渲染:

function BaseComponent({ a, b }) {
  // 當(dāng) a 改變時(shí)才會(huì)重新渲染
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // 當(dāng) b 改變時(shí)才會(huì)重新渲染
  const child2 = useMemo(() => <Child2 b=年鸳 />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
}

上面的例子只有a 發(fā)生改變的時(shí)候 Child1才會(huì)改變, b發(fā)生改變的時(shí)候 Child2才會(huì)改變。

如果想實(shí)現(xiàn)Class Component的shouldComponentUpdate方法丸相,可以使用React.memo方法搔确,區(qū)別是它只能比較 props,不會(huì)比較 state:

const BaseComponent = React.memo(({ a, b }) => {
  // 當(dāng) a 改變時(shí)才會(huì)重新渲染
  const child1 = useMemo(() => <Child1 a={a} />, [a]);
  // 當(dāng) b 改變時(shí)才會(huì)重新渲染
  const child2 = useMemo(() => <Child2 b= />, [b]);
  return (
    <>
      {child1}
      {child2}
    </>
  )
});

useImperativeHandle 和 forwardRef

    1. useImperativeHandle 可以讓你在使用 ref 時(shí)自定義暴露給父組件的實(shí)例值, useImperativeHandle 應(yīng)當(dāng)與 forwardRef一起使用
const SomeView = React.forwardRef(({isFollow},ref) => {
    const [follow,setFollow] = useState(!!isFollow);
    const followRef = useRef();
    useEffect(() => {
        // do something
    },[]);
//這個(gè)方法用來導(dǎo)出方法  外面的方法可以通過 Ref.current.function 調(diào)用
    useImperativeHandle(ref, () => ({
        setFollowState: (isFollow) => {
            if (!!followRef) {
                followRef.current.setFollowState(isFollow);
            }

        }
    }));
    return(
        <View style = {{
            width: 750,
            height: 450
            backgroundColor:'rgba(1,5,13,0.7)'}}>
            <FollowButton
                ref = {followRef}
                isFollow = {follow} />
        </View>
    );
});
const BigView =  (props) => {
    const someViewRef = useRef();
   
    const onChange = () => {
        someViewRef.current.setFollowState(false);
    }

    return (
        <View style = {{flex:1}}>
          <SomeView />
          <Button title = {'切換'} ref = {someViewRef} onPress = {onChange} />
        </View>
    );
}

export default React.memo(BigView);

從上面可以看出 useImperativeHandle 是function 組件調(diào)用模塊方法的途經(jīng).
ok膳算,先總結(jié)這么多座硕。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市涕蜂,隨后出現(xiàn)的幾起案子华匾,更是在濱河造成了極大的恐慌,老刑警劉巖机隙,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蜘拉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡有鹿,警方通過查閱死者的電腦和手機(jī)旭旭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葱跋,“玉大人您机,你說我怎么就攤上這事∧昃郑” “怎么了际看?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長矢否。 經(jīng)常有香客問我仲闽,道長,這世上最難降的妖魔是什么僵朗? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任赖欣,我火速辦了婚禮,結(jié)果婚禮上验庙,老公的妹妹穿的比我還像新娘顶吮。我一直安慰自己,他們只是感情好粪薛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布悴了。 她就那樣靜靜地躺著,像睡著了一般违寿。 火紅的嫁衣襯著肌膚如雪湃交。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天藤巢,我揣著相機(jī)與錄音搞莺,去河邊找鬼。 笑死掂咒,一個(gè)胖子當(dāng)著我的面吹牛才沧,可吹牛的內(nèi)容都是我干的迈喉。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼温圆,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼挨摸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捌木,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤油坝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后刨裆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體澈圈,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年帆啃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瞬女。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡努潘,死狀恐怖诽偷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情疯坤,我是刑警寧澤报慕,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站压怠,受9級(jí)特大地震影響眠冈,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜菌瘫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一蜗顽、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧雨让,春花似錦雇盖、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至娃闲,卻和暖如春虚汛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皇帮。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蛋辈,地道東北人属拾。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓将谊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親渐白。 傳聞我的和親對(duì)象是個(gè)殘疾皇子尊浓,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 前言 本文全面介紹了React Hooks的所有API概念、用法纯衍、豐富的demo以及部分底層原理栋齿。 實(shí)際上,Rea...
    南宮__閱讀 3,584評(píng)論 0 6
  • 使用 React Hooks 相比于從前的類組件有以下幾點(diǎn)好處: 1.代碼可讀性更強(qiáng)襟诸,原本同一塊功能的代碼邏輯被拆...
    Kinderzhu閱讀 865評(píng)論 0 2
  • 在學(xué)會(huì)使用React Hooks之前瓦堵,可以先看一下相關(guān)原理學(xué)習(xí)React Hooks 前言 在 React 的世界...
    DC_er閱讀 9,095評(píng)論 1 16
  • 在React v16.8新增了Hook,它提供了在函數(shù)組件中訪問狀態(tài)和React生命周期等能力歌亲,這些函數(shù)可以在程序...
    小小小小小粽子閱讀 493評(píng)論 0 0
  • react 16.8 以后加上了 react hook菇用,它可以讓你在不編寫 class 的情況下使用 state ...
    forever_提拉米蘇閱讀 524評(píng)論 1 6