React Hooks

你還在為該使用無狀態(tài)組件(Function)還是有狀態(tài)組件(Class)而煩惱嗎佑刷?
——擁有了hooks隙袁,你再也不需要寫Class了臊诊,你的所有組件都將是Function芽世。
你還在為搞不清使用哪個生命周期鉤子函數(shù)而日夜難眠嗎?
——擁有了Hooks藻三,生命周期鉤子函數(shù)可以先丟一邊了洪橘。
你在還在為組件中的this指向而暈頭轉(zhuǎn)向嗎?
——既然Class都丟掉了棵帽,哪里還有this熄求?你的人生第一次不再需要面對this。
這樣看來逗概,說React Hooks是今年最勁爆的新特性真的毫不夸張弟晚。如果你也對react感興趣,或者正在使用react進行項目開發(fā)逾苫,答應我卿城,請一定抽出至少30分鐘的時間來閱讀本文好嗎?所有你需要了解的React Hooks的知識點铅搓,本文都涉及到了瑟押,相信完整讀完后你一定會有所收獲。

一個最簡單的Hooks

首先讓我們看一下一個簡單的有狀態(tài)組件:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

我們再來看一下使用hooks后的版本:

import { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

是不是簡單多了星掰!可以看到多望,Example變成了一個函數(shù)嫩舟,但這個函數(shù)卻有自己的狀態(tài)(count),同時它還可以更新自己的狀態(tài)(setCount)怀偷。這個函數(shù)之所以這么了不得至壤,就是因為它注入了一個hook--useState,就是這個hook讓我們的函數(shù)變成了一個有狀態(tài)的函數(shù)枢纠。
除了useState這個hook外像街,還有很多別的hook,比如useEffect提供了類似于componentDidMount等生命周期鉤子的功能晋渺,useContext提供了上下文(context)的功能等等镰绎。
Hooks本質(zhì)上就是一類特殊的函數(shù),它們可以為你的函數(shù)型組件(function component)注入一些特殊的功能木西。咦畴栖?這聽起來有點像被詬病的Mixins啊八千?難道是Mixins要在react中死灰復燃了嗎吗讶?當然不會了,等會我們再來談兩者的區(qū)別恋捆≌战裕總而言之,這些hooks的目標就是讓你不再寫class沸停,讓function一統(tǒng)江湖膜毁。

React為什么要搞一個Hooks?

想要復用一個有狀態(tài)的組件太麻煩了愤钾!
我們都知道react都核心思想就是瘟滨,將一個頁面拆成一堆獨立的,可復用的組件能颁,并且用自上而下的單向數(shù)據(jù)流的形式將這些組件串聯(lián)起來杂瘸。但假如你在大型的工作項目中用react,你會發(fā)現(xiàn)你的項目中實際上很多react組件冗長且難以復用伙菊。尤其是那些寫成class的組件败玉,它們本身包含了狀態(tài)(state),所以復用這類組件就變得很麻煩占业。

那之前绒怨,官方推薦怎么解決這個問題呢纯赎?答案是:渲染屬性(Render Props)高階組件(Higher-Order Components)谦疾。我們可以稍微跑下題簡單看一下這兩種模式。

渲染屬性指的是使用一個值為函數(shù)的prop來傳遞需要動態(tài)渲染的nodes或組件犬金。如下面的代碼可以看到我們的DataProvider組件包含了所有跟狀態(tài)相關的代碼念恍,而Cat組件則可以是一個單純的展示型組件六剥,這樣一來DataProvider就可以單獨復用了。

import Cat from 'components/cat'
class DataProvider extends React.Component {
  constructor(props) {
    super(props);
    this.state = { target: 'Zac' };
  }

  render() {
    return (
      <div>
        {this.props.render(this.state)}
      </div>
    )
  }
}

<DataProvider render={data => (
  <Cat target={data.target} />
)}/>

雖然這個模式叫Render Props峰伙,但不是說非用一個叫render的props不可疗疟,習慣上大家更常寫成下面這種:

...
<DataProvider>
  {data => (
    <Cat target={data.target} />
  )}
</DataProvider>

高階組件這個概念就更好理解了,說白了就是一個函數(shù)接受一個組件作為參數(shù)瞳氓,經(jīng)過一系列加工后,最后返回一個新的組件〉嘀看下面的代碼示例岭埠,withUser函數(shù)就是一個高階組件,它返回了一個新的組件音榜,這個組件具有了它提供的獲取用戶信息的功能庞瘸。

onst withUser = WrappedComponent => {
  const user = sessionStorage.getItem("user");
  return props => <WrappedComponent user={user} {...props} />;
};

const UserPage = props => (
  <div class="user-container">
    <p>My name is {props.user}!</p>
  </div>
);
export default withUser(UserPage);

以上這兩種模式看上去都挺不錯的,很多庫也運用了這種模式赠叼,比如我們常用的React Router擦囊。但我們仔細看這兩種模式,會發(fā)現(xiàn)它們會增加我們代碼的層級關系嘴办。最直觀的體現(xiàn)瞬场,打開devtool看看你的組件層級嵌套是不是很夸張吧。這時候再回過頭看我們上一節(jié)給出的hooks例子涧郊,是不是簡潔多了泌类,沒有多余的層級嵌套。把各種想要的功能寫成一個一個可復用的自定義hook底燎,當你的組件想用什么功能時刃榨,直接在組件里調(diào)用這個hook即可。



生命周期鉤子函數(shù)里的邏輯太亂了吧双仍!
我們通常希望一個函數(shù)只做一件事情枢希,但我們的生命周期鉤子函數(shù)里通常同時做了很多事情。比如我們需要在componentDidMount中發(fā)起ajax請求獲取數(shù)據(jù)朱沃,綁定一些事件監(jiān)聽等等苞轿。同時,有時候我們還需要在componentDidUpdate做一遍同樣的事情逗物。當項目變復雜后搬卒,這一塊的代碼也變得不那么直觀。
classes真的太讓人困惑了翎卓!
我們用class來創(chuàng)建react組件時契邀,還有一件很麻煩的事情,就是this的指向問題失暴。為了保證this的指向正確坯门,我們要經(jīng)常寫這樣的代碼:this.handleClick = this.handleClick.bind(this)微饥,或者是這樣的代碼:<button onClick={() => this.handleClick(e)}>。一旦我們不小心忘了綁定this古戴,各種bug就隨之而來欠橘,很麻煩。
還有一件讓我很苦惱的事情现恼。我在之前的react系列文章當中曾經(jīng)說過肃续,盡可能把你的組件寫成無狀態(tài)組件的形式,因為它們更方便復用叉袍,可獨立測試痹升。然而很多時候,我們用function寫了一個簡潔完美的無狀態(tài)組件畦韭,后來因為需求變動這個組件必須得有自己的state疼蛾,我們又得很麻煩的把function改成class。
在這樣的背景下艺配,Hooks便橫空出世了察郁!

什么是State Hooks?

回到一開始我們用的例子转唉,我們分解來看到底state hooks做了什么:

import { useState } from 'react';

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

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

聲明一個狀態(tài)變量

import { useState } from 'react';

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

useState是react自帶的一個hook函數(shù)皮钠,它的作用就是用來聲明狀態(tài)變量。useState這個函數(shù)接收的參數(shù)是我們的狀態(tài)初始值(initial state)赠法,它返回了一個數(shù)組麦轰,這個數(shù)組的第[0]項是當前當前的狀態(tài)值,第[1]項是可以改變狀態(tài)值的方法函數(shù)砖织。
所以我們做的事情其實就是款侵,聲明了一個狀態(tài)變量count,把它的初始值設為0侧纯,同時提供了一個可以更改count的函數(shù)setCount新锈。

上面這種表達形式,是借用了es6的數(shù)組解構(array destructuring)眶熬,它可以讓我們的代碼看起來更簡潔

let _useState = useState(0);
let count = _useState[0];
let setCount = _useState[1];

讀取狀態(tài)值

<p>You clicked {count} times</p>

是不是超簡單妹笆?因為我們的狀態(tài)count就是一個單純的變量而已,我們再也不需要寫成{this.state.count}這樣了娜氏。

更新狀態(tài)

  <button onClick={() => setCount(count + 1)}>
    Click me
  </button>

當用戶點擊按鈕時拳缠,我們調(diào)用setCount函數(shù),這個函數(shù)接收的參數(shù)是修改過的新狀態(tài)值贸弥。接下來的事情就交給react了窟坐,react將會重新渲染我們的Example組件,并且使用的是更新后的新的狀態(tài),即count=1狸涌。這里我們要停下來思考一下,Example本質(zhì)上也是一個普通的函數(shù)最岗,為什么它可以記住之前的狀態(tài)帕胆?
一個至關重要的問題
這里我們就發(fā)現(xiàn)了問題,通常來說我們在一個函數(shù)中聲明的變量般渡,當函數(shù)運行完成后懒豹,這個變量也就銷毀了(這里我們先不考慮閉包等情況),比如考慮下面的例子:

function add(n) {
    const result = 0;
    return result + 1;
}

add(1); //1
add(1); //1

不管我們反復調(diào)用add函數(shù)多少次驯用,結果都是1脸秽。因為每一次我們調(diào)用add時,result變量都是從初始值0開始的蝴乔。那為什么上面的Example函數(shù)每次執(zhí)行的時候记餐,都是拿的上一次執(zhí)行完的狀態(tài)值作為初始值?答案是:是react幫我們記住的薇正。至于react是用什么機制記住的片酝,我們可以再思考一下。
假如一個組件有多個狀態(tài)值怎么辦挖腰?
首先雕沿,useState是可以多次調(diào)用的,所以我們完全可以這樣寫:

function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

其次猴仑,useState接收的初始值沒有規(guī)定一定要是string/number/boolean這種簡單數(shù)據(jù)類型审轮,它完全可以接收對象或者數(shù)組作為參數(shù)。唯一需要注意的點是辽俗,之前我們的this.setState做的是合并狀態(tài)后返回一個新狀態(tài)疾渣,而useState是直接替換老狀態(tài)后返回新狀態(tài)。最后崖飘,react也給我們提供了一個useReducer的hook稳衬,如果你更喜歡redux式的狀態(tài)管理方案的話。
從ExampleWithManyStates函數(shù)我們可以看到坐漏,useState無論調(diào)用多少次薄疚,相互之間是獨立的。這一點至關重要赊琳。為什么這么說呢街夭?

其實我們看hook的“形態(tài)”,有點類似之前被官方否定掉的Mixins這種方案躏筏,都是提供一種“插拔式的功能注入”的能力板丽。而mixins之所以被否定,是因為Mixins機制是讓多個Mixins共享一個對象的數(shù)據(jù)空間,這樣就很難確保不同Mixins依賴的狀態(tài)不發(fā)生沖突埃碱。
而現(xiàn)在我們的hook猖辫,一方面它是直接用在function當中,而不是class砚殿;另一方面每一個hook都是相互獨立的啃憎,不同組件調(diào)用同一個hook也能保證各自狀態(tài)的獨立性。這就是兩者的本質(zhì)區(qū)別了似炎。

react是怎么保證多個useState的相互獨立的辛萍?
還是看上面給出的ExampleWithManyStates例子,我們調(diào)用了三次useState羡藐,每次我們傳的參數(shù)只是一個值(如42贩毕,‘banana’),我們根本沒有告訴react這些值對應的key是哪個仆嗦,那react是怎么保證這三個useState找到它對應的state呢辉阶?
答案是,react是根據(jù)useState出現(xiàn)的順序來定的瘩扼。我們具體來看一下

 //第一次渲染
  useState(42);  //將age初始化為42
  useState('banana');  //將fruit初始化為banana
  useState([{ text: 'Learn Hooks' }]); //...

  //第二次渲染
  useState(42);  //讀取狀態(tài)變量age的值(這時候傳的參數(shù)42直接被忽略)
  useState('banana');  //讀取狀態(tài)變量fruit的值(這時候傳的參數(shù)banana直接被忽略)
  useState([{ text: 'Learn Hooks' }]); //...

假如我們改一下代碼:

let showFruit = true;
function ExampleWithManyStates() {
  const [age, setAge] = useState(42);
  
  if(showFruit) {
    const [fruit, setFruit] = useState('banana');
    showFruit = false;
  }
 
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

這樣一來睛藻,

 //第一次渲染
  useState(42);  //將age初始化為42
  useState('banana');  //將fruit初始化為banana
  useState([{ text: 'Learn Hooks' }]); //...

  //第二次渲染
  useState(42);  //讀取狀態(tài)變量age的值(這時候傳的參數(shù)42直接被忽略)
  // useState('banana');  
  useState([{ text: 'Learn Hooks' }]); //讀取到的卻是狀態(tài)變量fruit的值,導致報錯

鑒于此邢隧,react規(guī)定我們必須把hooks寫在函數(shù)的最外層店印,不能寫在ifelse等條件語句當中,來確保hooks的執(zhí)行順序一致倒慧。

什么是Effect Hooks?

我們在上一節(jié)的例子中增加一個新功能:

import { useState, useEffect } from 'react';

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

  // 類似于componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 更新文檔的標題
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

我們對比著看一下按摘,如果沒有hooks,我們會怎么寫纫谅?

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

我們寫的有狀態(tài)組件炫贤,通常會產(chǎn)生很多的副作用(side effect),比如發(fā)起ajax請求獲取數(shù)據(jù)付秕,添加一些監(jiān)聽的注冊和取消注冊兰珍,手動修改dom等等。我們之前都把這些副作用的函數(shù)寫在生命周期函數(shù)鉤子里询吴,比如componentDidMount掠河,componentDidUpdate和componentWillUnmount。而現(xiàn)在的useEffect就相當與這些聲明周期函數(shù)鉤子的集合體猛计。它以一抵三唠摹。
同時,由于前文所說hooks可以反復多次使用奉瘤,相互獨立勾拉。所以我們合理的做法是,給每一個副作用一個單獨的useEffect鉤子。這樣一來藕赞,這些副作用不再一股腦堆在生命周期鉤子里成肘,代碼變得更加清晰。

useEffect做了什么斧蜕?

我們再梳理一遍下面代碼的邏輯:

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

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

首先双霍,我們聲明了一個狀態(tài)變量count,將它的初始值設為0惩激。然后我們告訴react店煞,我們的這個組件有一個副作用蟹演。我們給useEffecthook傳了一個匿名函數(shù)风钻,這個匿名函數(shù)就是我們的副作用。在這個例子里酒请,我們的副作用是調(diào)用browser API來修改文檔標題骡技。當react要渲染我們的組件時,它會先記住我們用到的副作用羞反。等react更新了DOM之后布朦,它再依次執(zhí)行我們定義的副作用函數(shù)。
這里要注意幾點:
第一昼窗,react首次渲染和之后的每次渲染都會調(diào)用一遍傳給useEffect的函數(shù)是趴。而之前我們要用兩個聲明周期函數(shù)來分別表示首次渲染(componentDidMount),和之后的更新導致的重新渲染(componentDidUpdate)澄惊。
第二唆途,useEffect中定義的副作用函數(shù)的執(zhí)行不會阻礙瀏覽器更新視圖,也就是說這些函數(shù)是異步執(zhí)行的掸驱,而之前的componentDidMount或componentDidUpdate中的代碼則是同步執(zhí)行的肛搬。這種安排對大多數(shù)副作用說都是合理的,但有的情況除外毕贼,比如我們有時候需要先根據(jù)DOM計算出某個元素的尺寸再重新渲染温赔,這時候我們希望這次重新渲染是同步發(fā)生的,也就是說它會在瀏覽器真的去繪制這個頁面前發(fā)生鬼癣。

useEffect怎么解綁一些副作用

這種場景很常見陶贼,當我們在componentDidMount里添加了一個注冊,我們得馬上在componentWillUnmount中待秃,也就是組件被注銷之前清除掉我們添加的注冊骇窍,否則內(nèi)存泄漏的問題就出現(xiàn)了。
怎么清除呢锥余?讓我們傳給useEffect的副作用函數(shù)返回一個新的函數(shù)即可腹纳。這個新的函數(shù)將會在組件下一次重新渲染之后執(zhí)行。這種模式在一些pubsub模式的實現(xiàn)中很常見〕盎校看下面的例子:

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // 一定注意下這個順序:告訴react在下次重新渲染組件之后足画,同時是下次調(diào)用ChatAPI.subscribeToFriendStatus之前執(zhí)行cleanup
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

這里有一個點需要重視!這種解綁的模式跟componentWillUnmount不一樣佃牛。componentWillUnmount只會在組件被銷毀前執(zhí)行一次而已淹辞,而useEffect里的函數(shù),每次組件渲染后都會執(zhí)行一遍俘侠,包括副作用函數(shù)返回的這個清理函數(shù)也會重新執(zhí)行一遍象缀。所以我們一起來看一下下面這個問題。

為什么要讓副作用函數(shù)每次組件更新都執(zhí)行一遍爷速?

我們先看以前的模式:

 componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

很清除央星,我們在componentDidMount注冊,再在componentWillUnmount清除注冊惫东。但假如這時候props.friend.id變了怎么辦莉给?我們不得不再添加一個componentDidUpdate來處理這種情況:

  componentDidUpdate(prevProps) {
    // 先把上一個friend.id解綁
    ChatAPI.unsubscribeFromFriendStatus(
      prevProps.friend.id,
      this.handleStatusChange
    );
    // 再重新注冊新但friend.id
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

看到了嗎?很繁瑣廉沮,而我們但useEffect則沒這個問題颓遏,因為它在每次組件更新后都會重新執(zhí)行一遍。所以代碼的執(zhí)行順序是這樣的:

1.頁面首次渲染
2.替friend.id=1的朋友注冊

3.突然friend.id變成了2
4.頁面重新渲染
5.清除friend.id=1的綁定
6.替friend.id=2的朋友注冊
怎么跳過一些不必要的副作用函數(shù)

按照上一節(jié)的思路滞时,每次重新渲染都要執(zhí)行一遍這些副作用函數(shù)叁幢,顯然是不經(jīng)濟的。怎么跳過一些不必要的計算呢坪稽?我們只需要給useEffect傳第二個參數(shù)即可曼玩。用第二個參數(shù)來告訴react只有當這個參數(shù)的值發(fā)生改變時,才執(zhí)行我們傳的副作用函數(shù)(第一個參數(shù))刽漂。

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 只有當count的值發(fā)生變化時演训,才會重新執(zhí)行`document.title`這一句

當我們第二個參數(shù)傳一個空數(shù)組[]時,其實就相當于只在首次渲染的時候執(zhí)行贝咙。也就是componentDidMount加componentWillUnmount的模式样悟。不過這種用法可能帶來bug,少用庭猩。

還有哪些自帶的Effect Hooks?

除了上文重點介紹的useState和useEffect窟她,react還給我們提供來很多有用的hooks:
useContext
useReducer
useCallback
useMemo
useRef
useImperativeMethods
useMutationEffect
useLayoutEffect
我不再一一介紹,大家自行去查閱官方文檔蔼水。

怎么寫自定義的Effect Hooks?

為什么要自己去寫一個Effect Hooks? 這樣我們才能把可以復用的邏輯抽離出來震糖,變成一個個可以隨意插拔的“插銷”,哪個組件要用來趴腋,我就插進哪個組件里吊说,so easy论咏!看一個完整的例子,你就明白了
比如我們可以把上面寫的FriendStatus組件中判斷朋友是否在線的功能抽出來颁井,新建一個useFriendStatus的hook專門用來判斷某個id是否在線厅贪。

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

這時候FriendStatus組件就可以簡寫為:

function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

簡直Perfect!假如這個時候我們又有一個朋友列表也需要顯示是否在線的信息:

function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);

  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

現(xiàn)階段的理解,歡迎修改不足之處

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雅宾,一起剝皮案震驚了整個濱河市养涮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌眉抬,老刑警劉巖贯吓,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異蜀变,居然都是意外死亡悄谐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進店門昏苏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尊沸,“玉大人威沫,你說我怎么就攤上這事贤惯。” “怎么了棒掠?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵孵构,是天一觀的道長。 經(jīng)常有香客問我烟很,道長颈墅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任雾袱,我火速辦了婚禮恤筛,結果婚禮上,老公的妹妹穿的比我還像新娘芹橡。我一直安慰自己毒坛,他們只是感情好,可當我...
    茶點故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布林说。 她就那樣靜靜地躺著煎殷,像睡著了一般。 火紅的嫁衣襯著肌膚如雪腿箩。 梳的紋絲不亂的頭發(fā)上豪直,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機與錄音珠移,去河邊找鬼弓乙。 笑死末融,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的暇韧。 我是一名探鬼主播滑潘,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锨咙!你這毒婦竟也來了语卤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤酪刀,失蹤者是張志新(化名)和其女友劉穎粹舵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骂倘,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡眼滤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了历涝。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诅需。...
    茶點故事閱讀 37,997評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖荧库,靈堂內(nèi)的尸體忽然破棺而出堰塌,到底是詐尸還是另有隱情,我是刑警寧澤分衫,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布场刑,位于F島的核電站,受9級特大地震影響蚪战,放射性物質(zhì)發(fā)生泄漏牵现。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一邀桑、第九天 我趴在偏房一處隱蔽的房頂上張望瞎疼。 院中可真熱鬧,春花似錦壁畸、人聲如沸贼急。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽竿裂。三九已至,卻和暖如春照弥,著一層夾襖步出監(jiān)牢的瞬間腻异,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工这揣, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留悔常,地道東北人影斑。 一個月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓,卻偏偏與公主長得像机打,于是被迫代替她去往敵國和親矫户。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,722評論 2 345

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

  • 作為一個合格的開發(fā)者残邀,不要只滿足于編寫了可以運行的代碼皆辽。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個周閱讀 8,422評論 1 33
  • Effect Hook可以使得你在函數(shù)組件中執(zhí)行一些帶有副作用的方法芥挣。 上面這段代碼是基于上個state hook...
    xiaohesong閱讀 4,328評論 0 0
  • 原教程內(nèi)容詳見精益 React 學習指南驱闷,這只是我在學習過程中的一些閱讀筆記,個人覺得該教程講解深入淺出空免,比目前大...
    leonaxiong閱讀 2,810評論 1 18
  • 沒有華麗的修飾空另,沒有過多的強調(diào),我們用平實鏡頭與簡單的文字記錄下了北泰班主任的一天蹋砚。 早上6:45起床 早晨叫醒孩...
    小小小作zuo家閱讀 459評論 0 1
  • 1.自我管理--感覺自己的目標感是分情況的扼菠,有的目標能很快速的精準的完成,盡管慢一些坝咐,但有的目標制定好了以后沒有后...
    kidII閱讀 156評論 0 1