React Hook

什么是Hook

Hook 是 React 16.8 的新增特性,用途是在函數(shù)組件中使用state肢预、生命周期函數(shù)等其他react特性矛洞,而不用class組件。

Hook 使用規(guī)則

Hook 就是 JavaScript 函數(shù)烫映。

  • 只能在函數(shù)最外層調(diào)用 Hook沼本。不要在循環(huán)、條件判斷或者子函數(shù)中調(diào)用锭沟。
  • 只能在 React 的函數(shù)組件和自定義的 Hook 中調(diào)用 Hook抽兆。不要在其他 JavaScript 函數(shù)中調(diào)用。

State Hook

在編寫(xiě)函數(shù)組件時(shí)族淮,如果需要添加state辫红,則可以使用state hook,而不用像以前一樣需要改寫(xiě)成class組件祝辣。

Hook 在 class 內(nèi)部是不起作用的贴妻。

useState(),接收一個(gè)參數(shù)state的初始值(數(shù)值蝙斜,字符串名惩,對(duì)象皆可),返回一個(gè)數(shù)組孕荠。數(shù)組的第一個(gè)值是當(dāng)前的state娩鹉,第二個(gè)值是更新state的函數(shù)攻谁。使用數(shù)組解構(gòu)的方式來(lái)接收這兩個(gè)值。一般格式為以下:

// 設(shè)置something初始值為'defaultValue'
const [something, setSomething] = useState('defaultValue') 

通過(guò)下面例子底循,可以比較使用hook和class組件不同:
Hook

import React, { useState } from 'react';

function Example() {
  // 聲明一個(gè)叫 "count" 的 state 變量
  const [count, setCount] = useState(0);

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

class組件

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>
    );
  }
}

可以看出:count等價(jià)于this.state.count巢株,setCount(count+1)等價(jià)于this.setState({count: count+1})。

使用多個(gè) state 變量

使用多個(gè)state熙涤,只需要多次調(diào)用useState()阁苞。也可以用一個(gè)對(duì)象來(lái)儲(chǔ)存所有的state,但是這樣更新state時(shí)祠挫,需要自己處理其中的合并邏輯(通常使用擴(kuò)展運(yùn)算符...)那槽,具體可參考FAQ中關(guān)于分離獨(dú)立 state 變量的建議。

Effect Hook

Effect Hook 使我們可以在函數(shù)組件中執(zhí)行副作用操作等舔。

  • 數(shù)據(jù)獲取骚灸,設(shè)置訂閱以及手動(dòng)更改 React 組件中的 DOM 都屬于副作用。
  • useEffect() 可以看做 componentDidMount慌植,componentDidUpdate 和 componentWillUnmount 的組合甚牲。

無(wú)需清除的 effect

在 React 更新 DOM 之后運(yùn)行一些額外的代碼。比如發(fā)送網(wǎng)絡(luò)請(qǐng)求蝶柿,手動(dòng)變更 DOM丈钙,記錄日志等,都是常見(jiàn)的無(wú)需清除的操作交汤。因?yàn)檫@些操作執(zhí)行完之后雏赦,就可以忽略了。

useEffect()

useEffect()接收兩個(gè)參數(shù)芙扎,第一個(gè)參數(shù)是一個(gè)函數(shù)星岗,并且在執(zhí)行 DOM 更新之后調(diào)用這個(gè)函數(shù),第二個(gè)是可選參數(shù)戒洼,是一個(gè)數(shù)組俏橘,如果數(shù)組中的值在兩次重渲染之間沒(méi)有發(fā)生變化,可以通知 React 跳過(guò)對(duì) effect 的調(diào)用施逾。這個(gè)函數(shù)通常稱(chēng)之為effect敷矫,即副作用。使用這個(gè)hook汉额,可以告訴 React 組件需要在渲染后執(zhí)行某些操作。

  • 將 useEffect 放在組件內(nèi)部榨汤,使我們可以在 effect 中直接訪(fǎng)問(wèn) state 變量(或其他 props)蠕搜。
  • 默認(rèn)情況下,第一次渲染之后和每次更新之后都會(huì)執(zhí)行useEffect收壕。
  • 保證了每次運(yùn)行 effect 的同時(shí)妓灌,DOM 都已經(jīng)更新完畢轨蛤,不用再去考慮“掛載”還是“更新”。
  • 使用 useEffect 調(diào)度的 effect 不會(huì)阻塞瀏覽器更新屏幕虫埂,這樣使得應(yīng)用看起來(lái)響應(yīng)更快祥山。

通過(guò)下面例子,將 document 的 title 設(shè)置為包含了點(diǎn)擊次數(shù)的消息掉伏,可以比較使用hook和class組件不同:
hook

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

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

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

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

class

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>
    );
  }
}

需要清除的 effect

有一些副作用是需要清除的缝呕,例如訂閱外部數(shù)據(jù)源。這種情況下斧散,清除工作是非常重要的供常,可以防止引起內(nèi)存泄露。
class組件通常會(huì)在 componentDidMount 中設(shè)置訂閱鸡捐,并在 componentWillUnmount 中清除它栈暇。
通過(guò)下面例子,假設(shè)我們有一個(gè) ChatAPI 模塊箍镜,它允許我們訂閱好友的在線(xiàn)狀態(tài)源祈,可以比較使用hook和class組件不同:

  • 如果 effect 返回一個(gè)函數(shù),React 將會(huì)在執(zhí)行清除操作時(shí)調(diào)用它色迂。這是 effect 可選的清除機(jī)制香缺。每個(gè) effect 都可以返回一個(gè)清除函數(shù)。如此可以將添加和移除訂閱的邏輯放在一起脚草。它們都屬于 effect 的一部分赫悄。
  • React 會(huì)在組件卸載的時(shí)候執(zhí)行清除操作。
  • 并不是必須為 effect 中返回的函數(shù)命名馏慨,也可以返回一個(gè)箭頭函數(shù)埂淮。

hook

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

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

  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    // Specify how to clean up after this effect:
    return function cleanup() {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

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

class

class FriendStatus extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  componentWillUnmount() {
    ChatAPI.unsubscribeFromFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }
  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }

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

使用多個(gè) Effect 實(shí)現(xiàn)關(guān)注點(diǎn)分離

用 Hook 其中一個(gè)目的就是要解決 class組件 中生命周期函數(shù)經(jīng)常包含不相關(guān)的邏輯,但又把相關(guān)邏輯分離到了幾個(gè)不同方法中的問(wèn)題写隶。就像使用多個(gè) state 的 Hook一樣倔撞,也可以使用多個(gè) effect,將不相關(guān)邏輯分離到不同的 effect 中慕趴。

  • Hook 允許按照代碼的用途分離各個(gè)effect痪蝇,而不是像生命周期函數(shù)那樣。
  • React 將按照 effect 聲明的順序依次調(diào)用組件中的每一個(gè) effect冕房。
    通過(guò)下面例子可以發(fā)現(xiàn)躏啰,在class組件中,設(shè)置 document.title 的邏輯被分割到 componentDidMount 和 componentDidUpdate 中耙册,訂閱邏輯被分割到 componentDidMount 和 componentWillUnmount 中给僵。而且 componentDidMount 中同時(shí)包含了兩個(gè)不同功能的代碼。
    hook
function FriendStatusWithCounter(props) {
  const [count, setCount] = useState(0);
  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });

  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }

    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  // ...
}

class

class FriendStatusWithCounter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0, isOnline: null };
    this.handleStatusChange = this.handleStatusChange.bind(this);
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

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

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

  handleStatusChange(status) {
    this.setState({
      isOnline: status.isOnline
    });
  }
  // ...

為什么每次更新的時(shí)候都要運(yùn)行 Effect

effect 的清除階段在每次重新渲染時(shí)都會(huì)執(zhí)行,而不是只在卸載組件的時(shí)候執(zhí)行一次帝际。這個(gè)設(shè)計(jì)可以幫助我們創(chuàng)建 bug 更少的組件蔓同。
示例,從 class 中 props 讀取 friend.id蹲诀,然后在組件掛載后訂閱好友的狀態(tài)斑粱,并在卸載組件的時(shí)候取消訂閱:

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

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

但是當(dāng)組件已經(jīng)顯示在屏幕上時(shí),friend prop 發(fā)生變化時(shí)脯爪,這個(gè)組件將繼續(xù)展示原來(lái)的好友狀態(tài)则北。這是一個(gè) bug,而且還會(huì)因?yàn)槿∠嗛啎r(shí)使用錯(cuò)誤的好友 ID 導(dǎo)致內(nèi)存泄露或崩潰的問(wèn)題披粟。內(nèi)存泄露是指當(dāng)一塊內(nèi)存不再被應(yīng)用程序使用的時(shí)候咒锻,由于某種原因,這塊內(nèi)存沒(méi)有返還給操作系統(tǒng)或者內(nèi)存池的現(xiàn)象守屉。
在 class 組件中惑艇,需要添加 componentDidUpdate 來(lái)解決這個(gè)問(wèn)題:

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

  componentDidUpdate(prevProps) {
    // 取消訂閱之前的 friend.id
    ChatAPI.unsubscribeFromFriendStatus(
      prevProps.friend.id,
      this.handleStatusChange
    );
    // 訂閱新的 friend.id
    ChatAPI.subscribeToFriendStatus(
      this.props.friend.id,
      this.handleStatusChange
    );
  }

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

hook

function FriendStatus(props) {
  // ...
  useEffect(() => {
    // ...
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

并不需要特定的代碼來(lái)處理更新邏輯,因?yàn)?useEffect 默認(rèn)就會(huì)處理拇泛。它會(huì)在調(diào)用一個(gè)新的 effect 之前對(duì)前一個(gè) effect 進(jìn)行清理滨巴。例如

// 掛載: { friend: { id: 100 } }
ChatAPI.subscribeToFriendStatus(100, handleStatusChange);     // 運(yùn)行第一個(gè) effect

// 更新: { friend: { id: 200 } }
ChatAPI.unsubscribeFromFriendStatus(100, handleStatusChange); // 清除上一個(gè) effect
ChatAPI.subscribeToFriendStatus(200, handleStatusChange);     // 運(yùn)行下一個(gè) effect

// 更新: { friend: { id: 300 } }
ChatAPI.unsubscribeFromFriendStatus(200, handleStatusChange); // 清除上一個(gè) effect
ChatAPI.subscribeToFriendStatus(300, handleStatusChange);     // 運(yùn)行下一個(gè) effect

// 卸載
ChatAPI.unsubscribeFromFriendStatus(300, handleStatusChange); // 清除最后一個(gè) effect

此默認(rèn)行為保證了一致性,避免了在 class 組件中因?yàn)闆](méi)有處理更新邏輯而導(dǎo)致常見(jiàn)的 bug俺叭。

通過(guò)跳過(guò) Effect 進(jìn)行性能優(yōu)化

在某些情況下恭取,每次渲染后都執(zhí)行清理或者執(zhí)行 effect 可能會(huì)導(dǎo)致性能問(wèn)題。
在 class 組件中熄守,可以通過(guò)在 componentDidUpdate 中添加對(duì) prevProps 或 prevState 的比較邏輯解決:

componentDidUpdate(prevProps, prevState) {
  if (prevState.count !== this.state.count) {
    document.title = `You clicked ${this.state.count} times`;
  }
}

在 useEffect 中蜈垮,如果某些特定值在兩次重渲染之間沒(méi)有發(fā)生變化,可以傳遞數(shù)組作為 useEffect 的第二個(gè)可選參數(shù)裕照,通知 React 跳過(guò)對(duì) effect 的調(diào)用攒发。

useEffect(() => {
  document.title = `You clicked ${count} times`;
}, [count]); // 僅在 count 更改時(shí)更新

對(duì)于有清除操作的 effect 同樣適用:

useEffect(() => {
  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  return () => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  };
}, [props.friend.id]); // 僅在 props.friend.id 發(fā)生變化時(shí),重新訂閱
  • 如果要使用此優(yōu)化方式晋南,需確保數(shù)組中包含了所有外部作用域中會(huì)隨時(shí)間變化并且在 effect 中使用的變量惠猿,否則會(huì)引用到先前渲染中的舊變量。
  • 如果想執(zhí)行只運(yùn)行一次的 effect(僅在組件掛載和卸載時(shí)執(zhí)行)负间,可以傳遞一個(gè)空數(shù)組([])作為第二個(gè)參數(shù)偶妖。這就告訴 React 你的 effect 不依賴(lài)于 props 或 state 中的任何值,所以它永遠(yuǎn)都不需要重復(fù)執(zhí)行政溃。

Hook規(guī)則

只在最頂層使用 Hook
不要在循環(huán)趾访,條件或嵌套函數(shù)中調(diào)用 Hook, 確倍總是在 React 函數(shù)的最頂層調(diào)用腹缩。遵守這條規(guī)則,能確保 Hook 在每一次渲染中都按照同樣的順序被調(diào)用空扎。這讓 React 能夠在多次的 useState 和 useEffect 調(diào)用之間保持 hook 狀態(tài)的正確藏鹊。如果想要有條件地執(zhí)行一個(gè) effect,可以將判斷放到 Hook 的內(nèi)部转锈。
只在 React 函數(shù)中調(diào)用 Hook
不要在普通的 JavaScript 函數(shù)中調(diào)用 Hook盘寡。

  • 在 React 的函數(shù)組件中調(diào)用 Hook。
  • 在自定義 Hook 中調(diào)用其他 Hook撮慨。
    遵循此規(guī)則竿痰,確保組件的狀態(tài)邏輯在代碼中清晰可見(jiàn)。
    可以通過(guò) eslint-plugin-react-hooks 的 ESLint 插件來(lái)強(qiáng)制執(zhí)行這兩條規(guī)則砌溺。
npm install eslint-plugin-react-hooks --save-dev // 安裝
// eslint配置
{
  "plugins": [
    // ...
    "react-hooks"
  ],
  "rules": {
    // ...
    "react-hooks/rules-of-hooks": "error", // 檢查 Hook 的規(guī)則
    "react-hooks/exhaustive-deps": "warn" // 檢查 effect 的依賴(lài)
  }
}

自定義 Hook

自定義 Hook 是一個(gè)函數(shù)锡搜,其名稱(chēng)以 “use” 開(kāi)頭讲竿,函數(shù)內(nèi)部可以調(diào)用其他的 Hook。
兩個(gè)函數(shù)之間有共享邏輯時(shí),通常會(huì)把共用部分提取到第三個(gè)函數(shù)中槽华。而組件和 Hook 都是函數(shù),所以也同樣適用這種方式吹榴。

提取自定義Hook

useFriendStatus 自定義Hook

import { 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;
}
  • 確保只在自定義 Hook 的頂層無(wú)條件地調(diào)用其他 Hook暖哨,與組件中使用Hook的規(guī)則一致。
  • 函數(shù)名字必須以 use 開(kāi)頭培慌,參數(shù)與返回?zé)o要求豁陆,根據(jù)實(shí)際情況自定義

使用自定義Hook

在 FriendStatus 和 FriendListItem 組件中使用自定義的useFriendStatus Hook。

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>
  );
}

Hook API 索引

Hook FAQ

Hook的常見(jiàn)問(wèn)題

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吵护,一起剝皮案震驚了整個(gè)濱河市盒音,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌馅而,老刑警劉巖祥诽,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異用爪,居然都是意外死亡原押,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)偎血,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)诸衔,“玉大人,你說(shuō)我怎么就攤上這事颇玷”颗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵帖渠,是天一觀(guān)的道長(zhǎng)谒亦。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么份招? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任切揭,我火速辦了婚禮,結(jié)果婚禮上锁摔,老公的妹妹穿的比我還像新娘廓旬。我一直安慰自己,他們只是感情好谐腰,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布孕豹。 她就那樣靜靜地躺著,像睡著了一般十气。 火紅的嫁衣襯著肌膚如雪励背。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天砸西,我揣著相機(jī)與錄音叶眉,去河邊找鬼。 笑死籍胯,一個(gè)胖子當(dāng)著我的面吹牛竟闪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播杖狼,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼炼蛤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了蝶涩?” 一聲冷哼從身側(cè)響起理朋,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绿聘,沒(méi)想到半個(gè)月后嗽上,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡熄攘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年兽愤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片挪圾。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浅萧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出哲思,到底是詐尸還是另有隱情洼畅,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布棚赔,位于F島的核電站帝簇,受9級(jí)特大地震影響徘郭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜丧肴,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一残揉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闪湾,春花似錦冲甘、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)濒憋。三九已至何暇,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凛驮,已是汗流浹背裆站。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留黔夭,地道東北人宏胯。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像本姥,于是被迫代替她去往敵國(guó)和親肩袍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

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