React中Hooks的useRef 的高級(jí)用法

React中的Refs為我們提供了一種在組件的整個(gè)生命周期中存儲(chǔ)可變值的方法,并且通常用于與DOM交互而無(wú)需重新渲染組件。換句話說(shuō),我們不需要依賴狀態(tài)管理來(lái)使用Refs更新元素。這在某些特定的使用案例中非常有用,但在代替狀態(tài)管理或生命周期方法集成時(shí)班眯,也被視為一種反模式。

hooks已經(jīng)集成到react的框架中烁巫,使用生命周期的類組件署隘,現(xiàn)在可以替換成為函數(shù)組件和hooks。

useRefhook已實(shí)現(xiàn)為在函數(shù)組件中使用React ref的解決方案程拭。在本文中定踱,我們將與其他可以一起工作的鉤子一起探索這個(gè)鉤子。更具體地說(shuō)恃鞋,我們將:

  • 介紹如何將useRefhook與函數(shù)組件結(jié)合使用崖媚,并介紹與useEffect和共同使用的hook的一些用例useLayoutEffect
  • 如何useRef與并發(fā)React一起正確使用
  • 探索useRef演示組件的用例

這里我們主要關(guān)注function組件,盡管這絕不意味著它們應(yīng)該在類組件上使用恤浪,這也帶來(lái)了它們的好處畅哑。

將項(xiàng)目移至函數(shù)組件是否值得?

函數(shù)組件提供速度和樣板優(yōu)化的地方水由,類組件提供了久經(jīng)考驗(yàn)的組件生命周期方法和眾所周知的結(jié)構(gòu)荠呐,我們都已經(jīng)習(xí)慣了(使用this類屬性等)。

為了促進(jìn)代碼的一致性砂客,開(kāi)發(fā)人員通常選擇對(duì)項(xiàng)目使用純類組件方法或純函數(shù)組件方法泥张。我個(gè)人選擇創(chuàng)建函數(shù)組件作為我的默認(rèn)選擇,并退回到有意義的類組件鞠值,例如當(dāng)我想顯式定義生命周期方法媚创,許多類屬性等時(shí)。

以我的經(jīng)驗(yàn)彤恶,Typescript似乎比功能性組件更多地補(bǔ)充了類組件钞钙,能夠?qū)㈩愋鸵约皩傩院头椒ú迦腩愋捅旧眦佟n惥哂懈敿?xì)的結(jié)構(gòu)。

在任何情況下芒炼,React Ref都可以在類和函數(shù)組件中使用瘫怜。讓我們探討一下如何使用帶有useRef鉤子的引用。

使用 useRef Hook

函數(shù)組件Ref的實(shí)現(xiàn)已通過(guò)名為的鉤子實(shí)現(xiàn)useRef本刽。讓我們看看它是如何集成的鲸湃,然后探究它的特性以及何時(shí)使用它。

Ref可以在組件內(nèi)定義:

import React, { useRef } from 'react';
...
const refContainer = useRef(initialValue);

這個(gè)鉤子有一個(gè)非常簡(jiǎn)單的API-可以說(shuō)比它的類更簡(jiǎn)單盅安。選擇該refContainer名稱(來(lái)自官方文檔)以反映該變量實(shí)際上充當(dāng)基礎(chǔ)引用的容器唤锉。

為了與Refs的基類實(shí)現(xiàn)一致,被引用的對(duì)象本身存儲(chǔ)在current此容器變量的屬性中别瞭。有關(guān)此current屬性的兩個(gè)關(guān)鍵事實(shí):

  • 該屬性是可變的
  • 它可以在組件生命周期中隨時(shí)更改

函數(shù)組件仍然具有類組件的生命周期,盡管沒(méi)有生命周期方法株憾。組件生命周期的考慮將變得越來(lái)越重要蝙寨。

另外,initialValue我們上面?zhèn)魅氲膮?shù)可用于使用current默認(rèn)值進(jìn)行初始化嗤瞎。該值通常充當(dāng)占位符墙歪,直到我們實(shí)際引用DOM中的元素或?yàn)槠浞峙淙我庵禐橹埂?/p>

事件盡管Ref通常用于引用DOM元素,但它們也可以存儲(chǔ)原始類型和對(duì)象贝奇。我們將介紹這兩種情況的示例虹菲。

傳入的初始值也是完全合法的null:

//初始化一個(gè)空引用
const myRef = useRef(null);

無(wú)論current是什么,我們都可以在組件生命周期的任何時(shí)間log該屬性以查看其值:

//親自查看Ref實(shí)際引用的是什么
console.log(refContainer.current);

通過(guò)ref屬性完成對(duì)DOM元素的引用掉瞳。我們r(jià)eturn通過(guò)ref屬性在語(yǔ)句內(nèi)的JSX級(jí)別上執(zhí)行此操作毕源。下面使用button元素完全做到了這一點(diǎn):

// referencing a `button` element
...
render() {
  return(
    <button ref={refContainer}>
      Press Me
    </button>
  );
}

記住,我們引用的是DOM HTML元素陕习,而不是React組件霎褐。

如果引用的是按鈕,則將refContainer.current指向該<button />DOM元素该镣,從而使我們能夠訪問(wèn)諸如使按鈕聚焦/模糊的控件以及其樣式和事件處理程序(onClick例如冻璃,觸發(fā)click事件)。

模糊是用于使活動(dòng)元素處于非活動(dòng)狀態(tài)的術(shù)語(yǔ)损合。如果一個(gè)文本框處于活動(dòng)狀態(tài)(光標(biāo)在內(nèi)部閃爍省艳,準(zhǔn)備輸入文本),則可以通過(guò)單擊該元素外部的來(lái)模糊該元素以取消選擇它嫁审,或者通過(guò)編程使用諸如Refs之類的功能跋炕。

用refs管理按鈕狀態(tài)

讓我們來(lái)看一下useRef按鈕的第一個(gè)有效用例。

按鈕是一個(gè)很好的用例土居,可以與useRef按鈕一起使用枣购,從而可以控制按鈕的狀態(tài)(不要與組件狀態(tài)混淆)嬉探,而無(wú)需重新渲染整個(gè)組件。

讓我們考慮一個(gè)真實(shí)的場(chǎng)景棉圈。也許表單已經(jīng)完成涩堤,并且需要從默認(rèn)的禁用狀態(tài)啟用提交按鈕。僅為了執(zhí)行此操作而重新渲染我的整個(gè)表單將需要我:

  • 將所有當(dāng)前表單值保存到狀態(tài)
  • 使用這些當(dāng)前值再次重新渲染整個(gè)表單
  • 保持子組件中可能存在的任何其他狀態(tài)分瘾,例如驗(yàn)證消息和可視指示器
  • 重置可能發(fā)生的所有過(guò)渡或動(dòng)畫(huà)

React要在后臺(tái)處理很多工作胎围。只需引用DOM中的按鈕以切換其disabled屬性,在這里就更有意義了:

refContainer.current.setAttribute("disabled", true);
// or 
refContainer.current.removeAttribute("disabled");

到此為止德召,我們現(xiàn)在已經(jīng)介紹了的基本APIuseRef以及可行的用例-現(xiàn)在讓我們看看如何useRefuseEffecthook一起正確實(shí)現(xiàn)白魂。

在Commit組件階段正確實(shí)現(xiàn)useRef

為了完全理解如何實(shí)現(xiàn)useRef,我們需要了解React組件執(zhí)行的兩個(gè)階段上岗,以及這與React ref的工作如何聯(lián)系福荸。

可以在函數(shù)組件的主塊中定義Ref,但是在確定了將在Component中更新的內(nèi)容之后肴掷,必須在組件的commit階段中定義與Ref相關(guān)的任何副作用敬锐,例如事件偵聽(tīng)器或計(jì)時(shí)器。DOM發(fā)生呆瞻。讓我們更詳細(xì)地訪問(wèn)它台夺。

渲染與提交階段

一個(gè)組件經(jīng)歷兩個(gè)高級(jí)階段:

  • 所述渲染階段確定從先前的對(duì)DOM做出呈現(xiàn)的變化,并調(diào)用的方法痴脾,如componentWillMount颤介,render和setState(主要)
  • commit(提交)階段,顧名思義赞赖,提交更改(即呈現(xiàn)階段確定)的DOM滚朵,并調(diào)用方法,包括componentDidMount薯定,componentDidUpdate始绍,和componentDidCatch

如果要實(shí)現(xiàn)引用,則第一階段渲染具有我們需要關(guān)注的關(guān)鍵特征:在執(zhí)行提交階段之前可能會(huì)多次調(diào)用它–這是有問(wèn)題的话侄,在我們的應(yīng)用程序中引入了不可預(yù)測(cè)性和錯(cuò)誤的可能性亏推。

引用應(yīng)在提交階段實(shí)現(xiàn)

另一方面,提交階段只能調(diào)用一次年堆,這是我們應(yīng)該定義副作用的階段吞杭,通常來(lái)說(shuō),我們只希望實(shí)例化一次变丧。

副作用是任何會(huì)影響正在執(zhí)行的函數(shù)范圍之外的內(nèi)容的東西芽狗。這些可以是API請(qǐng)求,網(wǎng)絡(luò)套接字痒蓬,計(jì)時(shí)器童擎,記錄器滴劲,甚至是引用中的任何內(nèi)容。

如果某個(gè)組件重新渲染多次并在該階段重新初始化Ref顾复,則該Ref邏輯將執(zhí)行相同的次數(shù)班挖。當(dāng)我們考慮React中的并發(fā)模式時(shí),這更令人擔(dān)憂芯砸,因?yàn)榻M件的渲染階段可以在初始渲染上執(zhí)行多次萧芙。

這是因?yàn)椴l(fā)模式將渲染過(guò)程分解為多個(gè)部分,經(jīng)常在需要執(zhí)行其他更高優(yōu)先級(jí)的異步過(guò)程時(shí)暫停和恢復(fù)工作假丧。這樣做的結(jié)果是有可能在提交之前多次調(diào)用渲染階段生命周期方法(如果有錯(cuò)誤双揪,則根本不調(diào)用)。

定義副作用或超出組件范圍的任何內(nèi)容都是不可靠的包帚。我們可以做很多事情來(lái)確保在開(kāi)發(fā)時(shí)不會(huì)落入這些陷阱渔期。

1.使用嚴(yán)格模式

我們可以做的第一件事就是實(shí)現(xiàn)嚴(yán)格模式。嚴(yán)格模式旨在通過(guò)控制臺(tái)突出顯示應(yīng)用程序編碼的各種問(wèn)題渴邦,并有完整的章節(jié)專門(mén)用于檢測(cè)意外的副作用擎场。

可以通過(guò)JXS在整個(gè)應(yīng)用程序中啟用嚴(yán)格模式,也可以僅在一定數(shù)量的子組件上啟用嚴(yán)格模式几莽。包裝整個(gè)應(yīng)用程序以在整個(gè)過(guò)程中應(yīng)用嚴(yán)格模式:

// wrapping your app in Strict Mode
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
, document.getElementById('root'));

與一樣React.Fragment,嚴(yán)格模式不會(huì)在您的應(yīng)用中產(chǎn)生任何其他標(biāo)記宅静。

這是我偏愛(ài)的方法章蚣,可確保正確設(shè)計(jì)函數(shù)組件的邏輯,但還有其他選擇可用姨夹。

2.在并發(fā)模式下測(cè)試您的應(yīng)用

一種更直接的方法是在并發(fā)模式下開(kāi)發(fā)應(yīng)用程序纤垂,這還將在開(kāi)發(fā)過(guò)程中標(biāo)記問(wèn)題。

有兩種啟用并發(fā)模式的方法磷账,要么包裝元素的子集峭沦,要么使用并發(fā)模式聲明包裝整個(gè)應(yīng)用程序:

// section of an app (not final API)
<React.unstable_ConcurrentMode>
  <MyComponent />
</React.unstable_ConcurrentMode>
// entire app (not final API)
ReactDOM.unstable_createRoot(domNode).render(<App />);

這些不是最終的API,但是為開(kāi)發(fā)人員提供了至少一些測(cè)試React應(yīng)用程序異步版本的方法逃糟。該博客文章實(shí)際上建議使用嚴(yán)格模式作為準(zhǔn)備應(yīng)用程序并發(fā)的主要方法吼鱼。

由于進(jìn)行中的工作性質(zhì)不穩(wěn)定,建議不要在最終版本之前部署啟用并發(fā)模式的應(yīng)用程序的生產(chǎn)版本绰咽。

考慮到以上幾點(diǎn)菇肃,現(xiàn)在讓我們useRef在提交階段檢查一下實(shí)際完成的實(shí)現(xiàn)。

使用useEffect實(shí)現(xiàn)useRef

避免我們一直在討論的不可預(yù)測(cè)的Ref行為的解決方案是在useEffect or useLayoutEffect鉤子內(nèi)部實(shí)現(xiàn)Ref副作用取募。

為什么是這樣琐谤?因?yàn)楦鶕?jù)官方文檔,函數(shù)組件的主體內(nèi)部不允許出現(xiàn)諸如變異玩敏,訂閱斗忌,計(jì)時(shí)器和日志記錄之類的副作用质礼。該主體內(nèi)部的所有邏輯都在渲染階段執(zhí)行,因此導(dǎo)致UI中令人困惑的錯(cuò)誤和不一致织阳。

useEffect另一方面眶蕉,在瀏覽器中更新了實(shí)際的DOM,它將運(yùn)行一次陈哑。useEffect因此將在組件的提交階段運(yùn)行妻坝。

可以創(chuàng)建一個(gè)簡(jiǎn)單的計(jì)數(shù)器組件來(lái)演示這一點(diǎn),每次重新渲染組件時(shí)我們都在其中進(jìn)行計(jì)數(shù)惊窖。為了在單擊按鈕時(shí)強(qiáng)制重新渲染組件刽宪,useReducer還實(shí)現(xiàn)了該hook:


import React, { useEffect, useReducer, useRef } from "react";
const useForceRerender = () => useReducer(state => !state, false)[1];

const Counter = () => { 
  
  const forceRerender = useForceRerender();
  const refCount = useRef(0);
 
  useEffect(() => {
    refCount.current += 1;
  });
  
  return (
    <>
      <p>Count: {refCount.current}</p>
      <p>
        <button onClick={forceRerender}>
          Increment Counter
        </button>
      </p>
    </>;
  );
};

export default Counter;

在上面的示例中,refCount.current從值開(kāi)始0界酒,并在組件更新的提交階段遞增圣拄。

請(qǐng)記住,如果我們要在主功能塊中進(jìn)行此增量毁欣,則更新將在返回render函數(shù)之前在render階段進(jìn)行庇谆,使增量遭受不可預(yù)測(cè)的重復(fù)。

現(xiàn)在凭疮,讓我們看一下另一個(gè)引用DOM元素的組件饭耳,并通過(guò)其ref將事件偵聽(tīng)器附加到該組件。事件偵聽(tīng)器再次在useEffecthook中定義执解。此外寞肖,useEffect當(dāng)組件被卸載時(shí),act的返回函數(shù)可作為整齊的手段觸發(fā)衰腌,在這里我們可以從ref中刪除事件監(jiān)聽(tīng)器:

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

function App () {
  const refInput = useRef();

  useEffect(() => {
    const { current } = refInput;

    const handleFocus = () => {
      console.log('input is focussed');
    }
    const handleBlur = () => {
      console.log('input is blurred');
    }

    current.addEventListener('focus', handleFocus);
    current.addEventListener('blur', handleBlur);

    return () => {
      current.removeEventListener('focus', handleFocus);
      current.removeEventListener('blur', handleBlur);
    }
  });

  return (
    <p>
      <input
        type="text"
        ref={refInput}
        defaultValue="Focus me"
      />
    </p>
  );
}

export default App;

現(xiàn)在新蟆,如果您單擊文本輸入,然后單擊相應(yīng)的console.log輸出右蕊,則相應(yīng)的輸出將通知您該文本輸入正在聚焦和模糊琼稻。

讓我們進(jìn)一步了解這個(gè)概念。下一個(gè)示例通過(guò)refInputRef操作按鈕元素的類饶囚。我們還引入了<Wrapper />樣式化組件來(lái)定義一個(gè)active類帕翻,該類會(huì)更改文本輸入邊框和文本顏色:

import React, { useEffect, useRef } from 'react';
import styled from 'styled-components';

const Wrapper = styled.div`
  input {
    color: #666;
    border: 1px solid #ccc;
    outline: none;
    &.active {
      color: #000;
      border-color: #000;
    }
  }
`;

function App () {
  const refInput = useRef();

  useEffect(() => {
    const { current } = refInput;

    const handleFocus = () => {
      current.classList.add('active');
    }
    const handleBlur = () => {
      current.classList.remove('active');
    }

    current.addEventListener('focus', handleFocus);
    current.addEventListener('blur', handleBlur);

    return () => {
      current.removeEventListener('focus', handleFocus);
      current.removeEventListener('blur', handleBlur);
    }
  });

  return (
    <Wrapper>
      <input
        type="text"
        ref={refInput}
        defaultValue="Focus me"
      />
    </Wrapper>
  );
}

export default App;

現(xiàn)在,我們無(wú)需依賴狀態(tài)更新就可以進(jìn)行一些CSS操作坯约。

演示的最后階段是實(shí)現(xiàn)我們之前討論的內(nèi)容—實(shí)現(xiàn)一個(gè)Submit按鈕熊咽,如果文本輸入的值為空,則禁用它闹丐。為此横殴,我useRef為提交按鈕本身引入了一個(gè)額外的鉤子。為了切換disabled屬性,RefsetAttribute和removeAttributeJavascript API已被使用refSubmit衫仑。

完整的解決方案如下:

import React, { useEffect, useRef } from 'react';
import styled from 'styled-components';

const Wrapper = styled.div`
  .text {
    color: #666;
    border: 1px solid #ccc;
    outline: none;
    &.active {
      color: #000;
      border-color: #000;
    }
  }
`;

function App () {
  const refInput = useRef();
  const refSubmit = useRef();

  useEffect(() => {

    const { current } = refInput;

    const handleFocus = () => {
      current.classList.add('active');
    }

    const handleBlur = () => {
      current.classList.remove('active');

      current.value !== ''
        ? refSubmit.current.removeAttribute('disabled')
        : refSubmit.current.setAttribute('disabled', true);
    }

    current.addEventListener('focus', handleFocus);
    current.addEventListener('blur', handleBlur);

    return () => {
      current.removeEventListener('focus', handleFocus);
      current.removeEventListener('blur', handleBlur);
    }
  });

  return (
    <Wrapper>
      <p>
        <input
          className='text'
          type="text"
          ref={refInput}
          defaultValue="Focus me"
        />
      </p>
      <p>
        <input
          ref={refSubmit}
          type="submit"
          value="Submit"
        />
      </p>
    </Wrapper>
  );
}

export default App;

disabled一旦我們?cè)谖谋据斎胫鈫螕簦ɑ螯c(diǎn)擊)梨与,或者當(dāng)它變得模糊時(shí),提交按鈕的屬性就會(huì)更新文狱,這是確定表單是否有效的自然時(shí)間粥鞋。

one more thing

本文的最后一部分將介紹值得注意的使用技巧useRef。

當(dāng)useEffect引起問(wèn)題時(shí)瞄崇,請(qǐng)使用useLayoutEffect

在本文開(kāi)頭呻粹,我們提到了該useLayoutEffect鉤子,該鉤子也常與一起使用useRef苏研。useLayoutEffectcomponentDidMountcomponentDidUpdate類組件生命周期方法在同一階段觸發(fā)等浊,因此您可能傾向于使用它代替useEffect

但是摹蘑,官方文檔建議開(kāi)發(fā)人員應(yīng)useEffect主要嘗試使用筹燕,useLayoutEffect如果出現(xiàn)問(wèn)題請(qǐng)退后。使用會(huì)犧牲一些速度useLayoutEffect衅鹿,因?yàn)橹挥性谒蠨OM突變/更新都發(fā)生后才被同步調(diào)用-除了這個(gè)細(xì)節(jié)撒踪,它與相同useEffect

轉(zhuǎn)發(fā)useRef的

就像在類組件中初始化的轉(zhuǎn)發(fā)Refs一樣useRef大渤,只要遵循相同的約定制妄,也可以轉(zhuǎn)發(fā)通過(guò)鉤子初始化的Refs 。不要將ref作為“ ref”屬性傳遞-這是React中保留的屬性名稱泵三,會(huì)導(dǎo)致錯(cuò)誤忍捡。相反,一個(gè)名為的道具forwardRef切黔。

...
// defining `refInput` within `App`, forwarding it to `MyInput`
function App () {
  const refInput = useRef();
  return <MyInput 
    forwardRef={refInput};
}

// referencing `input` element with `forwardRef` in child component
function MyInput (props) {
  // verifying `input` is referenced correctly after DOM updates
  useLayoutEffect(() => {
    console.log(props.forwardRef.current);
  });
  const { forwardRef } = props;
  return (
    <input
      ref={forwardRef}
      type="submit"
      value="Submit"
  />);
}

用useRef切換焦點(diǎn)

除了監(jiān)聽(tīng)事件,我們還可以觸發(fā)事件具篇。如果我們不展示此演示纬霞,則演示將不完整。在下面的組件中驱显,單擊一個(gè)按鈕將再次關(guān)注另一個(gè)文本輸入诗芜,再次使用useRef:

// focussing an element with a button press
function TextInput () {
const refInput = useRef();
  function handleFocus () {
    refInput.current.focus();
  }
  return (
    <>
      <input ref={refInput} placeholder="Input Here..." />
      <button onClick={handleFocus}>Focus Input</button>
    </>
  );
}

以編程方式聚焦的元素可以改善用戶體驗(yàn),例如在第一次加載表單并自動(dòng)聚焦第一輸入時(shí)埃疫。

總結(jié)

本文是的useRef總結(jié)伏恐,并介紹了如何在考慮組件生命周期的情況下正確實(shí)現(xiàn)引用。對(duì)于這里討論的用例栓霜,使用refs可能是一種便捷的方法:

  • 使用焦點(diǎn)翠桦,模糊,禁用和其他與表單管理相關(guān)的屬性來(lái)微管理輸入
  • 要從元素中添加或刪除類,可能控制過(guò)渡或關(guān)鍵幀動(dòng)畫(huà)
  • 官方文檔中推薦的ref的另一個(gè)用例是與其他HTML5庫(kù)(例如媒體播放器)進(jìn)行交互销凑。這樣的庫(kù)將無(wú)法通過(guò)React狀態(tài)訪問(wèn)丛晌,而Refs為我們提供了一個(gè)后備功能,可以在與組件的生命周期一致的同時(shí)直接與其他元素進(jìn)行交互

參考

React: Using Refs with the useRef Hook

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末斗幼,一起剝皮案震驚了整個(gè)濱河市澎蛛,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌蜕窿,老刑警劉巖谋逻,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異桐经,居然都是意外死亡毁兆,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)次询,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)荧恍,“玉大人,你說(shuō)我怎么就攤上這事屯吊∷脱玻” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵盒卸,是天一觀的道長(zhǎng)骗爆。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蔽介,這世上最難降的妖魔是什么摘投? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮虹蓄,結(jié)果婚禮上犀呼,老公的妹妹穿的比我還像新娘。我一直安慰自己薇组,他們只是感情好外臂,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布细移。 她就那樣靜靜地躺著恩袱,像睡著了一般闹蒜。 火紅的嫁衣襯著肌膚如雪规丽。 梳的紋絲不亂的頭發(fā)上旬牲,一...
    開(kāi)封第一講書(shū)人閱讀 51,688評(píng)論 1 305
  • 那天伟端,我揣著相機(jī)與錄音痢畜,去河邊找鬼虫几。 笑死黑低,一個(gè)胖子當(dāng)著我的面吹牛赘艳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼第练,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼阔馋!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起娇掏,我...
    開(kāi)封第一講書(shū)人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤呕寝,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后婴梧,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體下梢,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年塞蹭,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了孽江。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡番电,死狀恐怖岗屏,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情漱办,我是刑警寧澤这刷,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站娩井,受9級(jí)特大地震影響暇屋,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜洞辣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一咐刨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扬霜,春花似錦定鸟、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蟹但,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間谭羔,已是汗流浹背华糖。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留瘟裸,地道東北人客叉。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親兼搏。 傳聞我的和親對(duì)象是個(gè)殘疾皇子卵慰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

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

  • 在React v16.8新增了Hook,它提供了在函數(shù)組件中訪問(wèn)狀態(tài)和React生命周期等能力佛呻,這些函數(shù)可以在程序...
    小小小小小粽子閱讀 493評(píng)論 0 0
  • 主要內(nèi)容 一裳朋、breaking changes? 二吓著、帶來(lái)什么好處鲤嫡? 三、哪些 api 绑莺?rule暖眼? 四、原理 五...
    good__day閱讀 731評(píng)論 0 1
  • React Hooks 在了解React Hooks之前, 我們先看一下 Class 和函數(shù)式 的一般寫(xiě)法 Cla...
    YM雨蒙閱讀 2,878評(píng)論 0 1
  • 原文地址:React Hooks: everything you need to know! ??[https://...
    _志銘閱讀 322評(píng)論 0 0
  • 什么是 Hooks 以往纺裁,React 組件都是通過(guò) class 的形式來(lái)編寫(xiě)诫肠,只有無(wú)狀態(tài)組件才可以用函數(shù)來(lái)編寫(xiě)。H...
    Actoress閱讀 1,095評(píng)論 0 0