React 組件與狀態(tài)

  • 組件名必須大寫(xiě)開(kāi)頭
  • 組件應(yīng)該在頂層定義。不要在組件函數(shù)里再定義其他組件。
  • 標(biāo)簽必須閉合若贮,例如使用<br/>而非<br>
  • 組件返回只能返回一個(gè)標(biāo)簽戳吝,如需要多個(gè)可以包裹到一個(gè)空的父級(jí)里浩销,如<>...</>(但只有其完整形式 <Fragment/> 可以接收 key 屬性):
import { Fragment } from 'react';

const listItems = people.map(person =>
  <Fragment key={person.id}>
    <h1>{person.name}</h1>
    <p>{person.bio}</p>
  </Fragment>
);

組件渲染流程

  1. 組件初次渲染,或組件或其祖先的狀態(tài)發(fā)生了改變骨坑,觸發(fā)組件渲染
  2. 組件渲染:執(zhí)行組件函數(shù)(不包括Hook)撼嗓,并在虛擬DOM樹(shù)中進(jìn)行diff運(yùn)算
    注意,組件函數(shù)必須都是沒(méi)有副作用的純函數(shù)欢唾。
  3. 瀏覽器繪制(DOM渲染):此時(shí)DOM才真正更新
  4. useEffect回調(diào)觸發(fā)

組件渲染的邏輯

每次組件渲染會(huì)重新執(zhí)行組件函數(shù)且警,但不包括其中的 Hook 內(nèi)容

純函數(shù)

組件應(yīng)當(dāng)都是純函數(shù),只負(fù)責(zé)自己的任務(wù)礁遣,不改變外部變量斑芜,且相同的輸入總得到相同的輸入。以此防止組件每次渲染時(shí)造成副作用祟霍。

Hook 內(nèi)容不會(huì)在組件再次渲染時(shí)重復(fù)執(zhí)行

父組件傳入的 props 如通過(guò)useState鏡像杏头,則父組件稍后傳遞不同的props時(shí)盈包,該state不會(huì)更新:

function Message({ messageColor }) {
  const [color, setColor] = useState(messageColor);
}

props

  • 父組件可以通過(guò) prop 傳遞數(shù)據(jù)、方法給子組件醇王。
  • 子組件通過(guò)解構(gòu)賦值來(lái)接收父組件傳遞進(jìn)來(lái)的數(shù)據(jù)和方法呢燥。
  • 組件定義時(shí)本身嵌套的JSX內(nèi)容會(huì)作為該組件的children prop(作用類似Vue的slot):
function Card({children}) {
  return <div>hello {children}</div>
}

export default function Profile() {
  return <Card><b>world</b></Card>
}
//最后會(huì)渲染成<div>hello <b>world</b></div>
  • 將本該子組件使用的state提升到父組件,再由父組件將state寓娩、setState通過(guò) props 傳入子組件供調(diào)用叛氨,這種操作稱為狀態(tài)提升
function MyApp() {
    function speak(name) {
        console.log("name", name);
    }
    return (
        <>
            <Child name="VV" speak={(name) => speak(name)} />
        </>
    );
}


function Child({ name, speak }) {
    return (
        <>
            <div>我的名字是{name}</div>
            <button onClick={() => speak(name)}>說(shuō)話</button>
        </>
    );
}
  • 組件也可以將自己從父組件獲得的props再傳遞給自己的子組件
    可以通過(guò)擴(kuò)展運(yùn)算符全部傳遞:
export default function Father(props) {
  return (
    <Child
      {...props}
    />
  );
}
function Child({ savedContact, onSave }) {
  ...
}

事件

  • 原生事件名在JSX中需要改為駝峰命名棘伴,如onClick寞埠。需要在捕獲階段觸發(fā)的事件在最后額外加上Capture,如onClickCapture焊夸。
  • 事件處理程序通常命名為 handle 接事件名仁连,例如:onClick={handleClick}
  • 當(dāng)需要指定函數(shù)入?yún)r(shí),可以使用箭頭函數(shù):onClick={() => handleClick(100)}
  • 父組件可以把事件通過(guò) props 傳遞給子組件阱穗,通常在 props 中的命名為 on 開(kāi)頭的大駝峰
  • 通過(guò)原生的e.stopPropagation()阻止冒泡饭冬,e.preventDefault()阻止默認(rèn)行為。

Hook 與狀態(tài)管理

以 use 開(kāi)頭的函數(shù)被稱為 Hook颇象,用于管理狀態(tài)伍伤。

  • Hook 只能在組件或其他 Hook(包括自定義Hook)的頂層調(diào)用,且不能出現(xiàn)在條件語(yǔ)句或循環(huán)中遣钳。
    Hook 不能被包裹在非組件且非 Hook 的普通自定義函數(shù)內(nèi)扰魂。
  • 可以將一些組件的公用邏輯抽出來(lái),作為自定義 Hook蕴茴。自定義 Hook 共享的是狀態(tài)邏輯劝评,而不是狀態(tài)本身(即被不同組件引用時(shí),內(nèi)容不互通)倦淀。
useState
const [state, setState] = useState(初始值)
  • state 狀態(tài)變量蒋畜,獨(dú)立于組件保存,組件多次渲染不會(huì)重定義該值撞叽。
  • setState 函數(shù)姻成,用于更新變量并觸發(fā)再次渲染
    函數(shù)入?yún)⒖梢允且粋€(gè)更新函數(shù)(必須為純函數(shù),只用于計(jì)算下一個(gè)狀態(tài)愿棋。多個(gè)更新函數(shù)會(huì)在渲染期間依次調(diào)用)科展,或一個(gè)固定值(本質(zhì)上是更新函數(shù)返回固定值的簡(jiǎn)寫(xiě))

注意,state在每次渲染中是固定的(快照)糠雨,setState不會(huì)改變當(dāng)前渲染中的state才睹,只會(huì)改變下一次渲染的值!
如想要在當(dāng)前渲染中就改變,可使用普通變量或useRef琅攘。
一個(gè)事件處理函數(shù)會(huì)全部執(zhí)行完再進(jìn)行渲染垮庐,稱為批處理

import { useState } from 'react';

export default function Counter() {
  const [number, setNumber] = useState(0);

  return (
    <>
      <h1>{number}</h1>
      <button onClick={() => {
        setNumber(10);
        setNumber(number + 1);
        setNumber(number + 1);
        setNumber(n=>n + 1);
        setNumber(n=>n + 1);
        console.log(number);//0
      }}>點(diǎn)擊后變成3</button>
    </>
  )
}
使用flushSync函數(shù)同步更新DOM

傳入flushSync執(zhí)行的setState操作會(huì)提前觸發(fā)DOM渲染(但快照中的state保持不變)坞琴,而不會(huì)等待批處理完成:

const [number, setNumber] = useState(0);
return (
   <>
       <h1 id="h1">{number}</h1>
       <button onClick={() => {
           flushSync(() => {
               setNumber(1);
               console.log(number);//0
               console.log(document.getElementById("h1").innerHTML);//0
           });
           console.log(number);//0
           console.log(document.getElementById("h1").innerHTML);//1
       }}>點(diǎn)我</button>
   </>
);
state 不保存在 JSX 標(biāo)簽里

state 與樹(shù)中放置該 JSX 的位置相關(guān)聯(lián)哨查。因此在渲染樹(shù)中相同位置的相同組件,其內(nèi)部狀態(tài)會(huì)得到保留:

//以下<Counter/>組件內(nèi)部的state置济,在 isFancy 切換時(shí)會(huì)得到保留
{isFancy ? (
  <Counter isFancy={true} /> 
) : (
  <Counter isFancy={false} /> 
)}

//以下<Counter/>組件內(nèi)部的state解恰,在 isPlayerA 切換時(shí)會(huì)重置(因位置不同)
{isPlayerA &&
  <Counter person="Taylor" />
}
{!isPlayerA &&
  <Counter person="Sarah" />
}

重置其內(nèi)部狀態(tài)的幾個(gè)方式:

  • 渲染樹(shù)中不同位置
    相同渲染樹(shù)需要:上級(jí)組件相同,且前置兄弟組件數(shù)量相同(<></>是一個(gè)組件浙于,DOM元素也視為一種組件,一段JSX{}也算一種組件)
  • 不同組件
  • 銷毀該組件后不立刻重新渲染該組件
  • 使用不同 key
突變 mutation

通過(guò) setState 以外的方式造成的 state 數(shù)據(jù)變化稱為突變(例如通過(guò)原生JS直接修改對(duì)象挟纱、數(shù)組的某個(gè)成員)羞酗。突變的結(jié)果會(huì)在下次渲染中顯示,但突變本身不會(huì)觸發(fā)渲染紊服。
應(yīng)當(dāng)避免突變的發(fā)生檀轨。


useReducer

當(dāng)需要在多處分別對(duì)同一state做出不同修改時(shí),可以通過(guò)useReducer代替useState進(jìn)行統(tǒng)一管理欺嗤。

  • useReducer可傳入兩個(gè)入?yún)⒉翁眩谝粋€(gè)是reducer函數(shù),第二個(gè)是state初始值煎饼。
  • reducer函數(shù)必須為純函數(shù)讹挎,只用于計(jì)算下一個(gè)狀態(tài)。(嚴(yán)格模式下會(huì)調(diào)用兩次)吆玖。該函數(shù)的返回值用于更新?tīng)顟B(tài)筒溃。
  • 返回的dispatch函數(shù)用來(lái) “派發(fā)” 用戶操作給 reducer 函數(shù),調(diào)用時(shí)傳入一個(gè)自定義參數(shù)(通常約定會(huì)有 type 屬性)沾乘,傳給 reducer 函數(shù)的第二個(gè)參數(shù):
import { useReducer } from 'react';
const [tasks, dispatch] = useReducer(tasksReducer, initialTasks);
function tasksReducer(tasks, action) {
  switch (action.type) {
    case 1:
      return{
        ...tasks,
        age: action.age
      }
    default: {
      throw Error('未知 action: ' + action.type);
    }
  }
}

useRef(脫圍)

類似useState怜奖,返回一個(gè)ref實(shí)例,用于在組件渲染間保留信息翅阵。
不要在渲染期間(即組件主體)讀取或?qū)懭?code>ref歪玲,應(yīng)該移到事件處理程序或者 Effect 中。

  • ref實(shí)例是一個(gè)具有current屬性的對(duì)象掷匠,其更新不會(huì)觸發(fā)組件渲染滥崩,也不是個(gè)快照,可以直接對(duì)current屬性賦值以修改信息槐雾。
  • ref實(shí)例通常用于儲(chǔ)存 timeout ID夭委、DOM元素、或其他不需要在JSX中渲染計(jì)算的內(nèi)容:
import { useRef } from 'react';
const ref = useRef(0);
ref.current = ref.current + 1;//1
  • JSX中DOM節(jié)點(diǎn)的ref屬性,可直接賦值為ref實(shí)例以綁定DOM元素株灸,也可以傳入一個(gè)方法崇摄,在方法內(nèi)手動(dòng)綁定DOM元素。
    當(dāng)傳入方法時(shí)慌烧,每當(dāng)組件重新渲染逐抑,先前的函數(shù)將被調(diào)用并傳遞 null 作為參數(shù),并且下一個(gè)函數(shù)將被調(diào)用并傳遞對(duì)應(yīng) DOM 節(jié)點(diǎn)作為參數(shù):
import { useRef } from 'react';
export default function Form() {
    const inputRef = useRef(null);
    const divRefs = useRef(new Map());
       return (
        <>
            <input ref={inputRef} />
            <button onClick={() => inputRef.current.focus()}>
                聚焦輸入框
            </button>

            {
                [0, 1, 2, 3, 4, 5].map(i => (
                    <div key={i} ref={node => {
                        if(node){
                            divRefs.current.set(i, node)
                        }else{
                            divRefs.current.delete(i)
                        }
                    }}
                        onClick={() => {
                            divRefs.current.get(i).style.color = "red";
                        }}>
                        我是第{i}個(gè)屹蚊,點(diǎn)我會(huì)變紅
                    </div>
                ))
            }
        </>
    );
}

上述方法默認(rèn)只能用于瀏覽器原生元素厕氨,當(dāng)用于JSX中的自定義組件時(shí),該組件需要由forwardRef方法創(chuàng)建(在此方法中還可以通過(guò)useImperativeHandle限制暴露的內(nèi)容):

import { forwardRef, useRef } from 'react';

const MyInput = forwardRef((props, ref) => {
  return <input {...props} ref={ref} />;
});

export default function Form() {
  const inputRef = useRef(null);

  return (
    <>
      <MyInput ref={inputRef} />
    </>
  );
}


useEffect(脫圍汹粤,由渲染引起的副作用命斧,與React之外的系統(tǒng)同步)
  • 處理 Effect 的函數(shù)(必傳)
    • 該函數(shù)在嚴(yán)格模式+開(kāi)發(fā)環(huán)境下會(huì)調(diào)用兩次。
    • 該函數(shù)可以返回一個(gè)清理函數(shù)嘱兼,會(huì)在組件卸載国葬,或Effect再次執(zhí)行前調(diào)用。
      注意清理函數(shù)在Effect函數(shù)內(nèi)是個(gè)閉包芹壕,因此調(diào)用時(shí)起內(nèi)容只影響其聲明時(shí)的Effect內(nèi)變量:
//此處返回值內(nèi)的ignore可以讓同一次調(diào)用中的fetch回調(diào)失效汇四,但不影響下一次的Effect
//可用于防止競(jìng)態(tài)條件,保證是最后一次觸發(fā)的生效
  useEffect(() => {
    let ignore = false;
    setBio(null);
    fetchBio(person).then(result => {
      if (!ignore) {
        setBio(result);
      }
    });
    return () => {
      ignore = true;
    }
  }, [person]);
  • 依賴數(shù)組(非必傳)
    • 若不傳踢涌,則會(huì)在組件每次渲染并調(diào)用觸發(fā)DOM渲染后調(diào)用函數(shù)通孽。
    • 若傳入依賴數(shù)組(可傳入stateprops睁壁、組件體內(nèi)聲明的利用前兩者計(jì)算得出的其他響應(yīng)式變量)背苦,且依賴內(nèi)容均和上次渲染時(shí)相同,則跳過(guò)本次Effect函數(shù)執(zhí)行堡僻。
      傳入依賴數(shù)組后糠惫,函數(shù)只能使用依賴數(shù)組內(nèi)包含的響應(yīng)式變量。
      • 類似location.pathname這樣的外部可變值不是響應(yīng)式變量钉疫,應(yīng)改用 useSyncExternalStore 來(lái)讀取和訂閱硼讽。
      • 當(dāng)前組件的ref不是響應(yīng)式變量,因?yàn)槠涫怯幸饪勺兊纳蟆⒎€(wěn)定的固阁。其變化不會(huì)觸發(fā)重新渲染
      • useState創(chuàng)建的setState方法不是響應(yīng)式變量
import { useEffect } from 'react';
useEffect(() => {
  // 這里的代碼會(huì)在每次渲染后執(zhí)行
});

useEffect(() => {
  // 這里的代碼只會(huì)在組件掛載后執(zhí)行
}, []);

useEffect(() => {
  //這里的代碼只會(huì)在每次渲染后,并且 a 或 b 的值與上次渲染不一致時(shí)執(zhí)行
}, [a, b]);

注意:組件內(nèi)聲明的對(duì)象城菊、數(shù)組备燃、函數(shù)等(包括父組件傳遞下來(lái)的props中的以上內(nèi)容),因?yàn)槊看武秩径疾蝗攘杌#绻麄鬟f給useEffect作為依賴則會(huì)導(dǎo)致每次渲染都觸發(fā)useEffect并齐。此時(shí)需要使用useMemouseCallback,或?qū)⒃撀暶饕苿?dòng)到組件外或Effect內(nèi)。
而當(dāng)某個(gè)響應(yīng)式變量既需要參與useEffect內(nèi)容况褪,又不想因其變化而導(dǎo)致觸發(fā)Effect撕贞,則可以使用useEffectEvent

useMemo 和 useCallback

useMemo 返回值测垛,useCallback 返回函數(shù)捏膨。兩者均用于避免組件每次渲染時(shí)的重復(fù)計(jì)算。

  • 需傳入依賴數(shù)組食侮,若依賴內(nèi)容均和上次渲染時(shí)相同号涯,則返回和上一次全等的結(jié)果。
  • 會(huì)在JSX渲染環(huán)節(jié)(即DOM更新前)生效锯七,因此都必須是純函數(shù)链快。
import { useMemo, useState, useCallback } from 'react';

function TodoList({ todos, filter }) {
  const [newTodo, setNewTodo] = useState('');
  // ? 除非 todos 或 filter 發(fā)生變化,否則不會(huì)重新執(zhí)行 getFilteredTodos()
  const visibleTodos = useMemo(() => getFilteredTodos(todos, filter), [todos, filter]);
  // ...
}
useEffectEvent

用于提取Effect中部分邏輯起胰,以實(shí)現(xiàn)如下功能:存在某個(gè)響應(yīng)式變量久又,既要在Effect中使用,又不想充當(dāng)Effect的依賴項(xiàng)效五。

相比于useCallback的區(qū)別:

  1. 不用顯式聲明依賴
  2. 即使依賴變了,fn的引用也不變(與原來(lái)全等)
  3. 只能在useEffect內(nèi)部使用炉峰,且不需要加入useEffect依賴
//在這里畏妖,onVisit 內(nèi)的 url 對(duì)應(yīng) 最新的 url(可能已經(jīng)變化了),但是 visitedUrl 對(duì)應(yīng)的是最開(kāi)始引起這個(gè) Effect(并且是本次 onVisit 調(diào)用)運(yùn)行的 url 疼阔。
import { experimental_useEffectEvent as useEffectEvent } from 'react';

const onVisit = useEffectEvent(visitedUrl => {
  logVisit(visitedUrl, numberOfItems);
});

useEffect(() => {
  setTimeout(() => {
    onVisit(url);
  }, 5000); // 延遲記錄訪問(wèn)
}, [url]);

使用 Immer 庫(kù)簡(jiǎn)化 useState 和 useReducer

Immer 庫(kù)可代替useStateuseReducer戒劫,以避免突變,并簡(jiǎn)化對(duì)象婆廊、數(shù)組的更新操作迅细。

npm install use-immer
useImmer

提供的修改方法,其參數(shù)同樣可以是一個(gè)更新函數(shù)或一個(gè)固定值淘邻。

  • 為固定值時(shí)效果同useState
  • 為更新函數(shù)時(shí)(通常以update開(kāi)頭命名)茵典,其參數(shù)(通常命名為draft)是一個(gè)Proxy而不是原始的state(類似 Vue3 實(shí)現(xiàn)了數(shù)據(jù)劫持),因此可以直接修改其中屬性:
import { useImmer } from 'use-immer';

const [person, updatePerson] = useImmer({
  name: 'Niki de Saint Phalle',
});

updatePerson(draft => {
  draft.name = e.target.value;
});
useImmerReducer

可以返回宾舅,也可以直接修改 draft 對(duì)象屬性统阿。
注意switch中如果不使用return,要使用break分隔case

import { useImmerReducer } from 'use-immer';

const [tasks, dispatch] = useImmerReducer(tasksReducer, [{id:1},{id:2},{id:3}]);
function tasksReducer(draft, action) {
  switch (action.type) {
    case 'changed': {
      const index = draft.findIndex((t) => t.id === action.task.id);
      draft[index] = action.task;
      break;
    }
    case 'deleted': {
      return draft.filter((t) => t.id !== action.id);
    }
    default: {
      throw Error('未知 action:' + action.type);
    }
  }
}

function handleChangeTask(task) {
  dispatch({
    type: 'changed',
    task: task,
  });
}

使用 Context 深層傳遞參數(shù)

用于祖先元素向其深層后代傳遞信息筹我,以代替 props 逐級(jí)下傳

// 單獨(dú)的文件 MyContext.js
import { createContext } from 'react';
export const MyContext = createContext("默認(rèn)值")

// 父組件提供Context扶平,Context.Provider的后代元素都可以獲得距離最近的值
import { MyContext } from './Context.js';
export default function App() {
  return (
    <>
      <MyContext.Provider value={100}>
      <List/>
      </MyContext.Provider>
    </>
  )
}

// 子組件獲取Context
import { useContext } from 'react';
import { MyContext } from './MyContext.js';
function List() {
  const data = useContext(MyContext)
  return <div>{data}</div>
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市蔬蕊,隨后出現(xiàn)的幾起案子结澄,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻献,死亡現(xiàn)場(chǎng)離奇詭異们妥,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)赎瑰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)王悍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人餐曼,你說(shuō)我怎么就攤上這事压储。” “怎么了源譬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵集惋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我踩娘,道長(zhǎng)刮刑,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任养渴,我火速辦了婚禮雷绢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘理卑。我一直安慰自己翘紊,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布藐唠。 她就那樣靜靜地躺著帆疟,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宇立。 梳的紋絲不亂的頭發(fā)上踪宠,一...
    開(kāi)封第一講書(shū)人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音妈嘹,去河邊找鬼柳琢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛蟋滴,可吹牛的內(nèi)容都是我干的染厅。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼津函,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼肖粮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起尔苦,我...
    開(kāi)封第一講書(shū)人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涩馆,失蹤者是張志新(化名)和其女友劉穎行施,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體魂那,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛾号,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涯雅。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鲜结。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖活逆,靈堂內(nèi)的尸體忽然破棺而出精刷,到底是詐尸還是另有隱情,我是刑警寧澤蔗候,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布怒允,位于F島的核電站,受9級(jí)特大地震影響锈遥,放射性物質(zhì)發(fā)生泄漏纫事。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一所灸、第九天 我趴在偏房一處隱蔽的房頂上張望丽惶。 院中可真熱鬧,春花似錦爬立、人聲如沸蚊夫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至壤圃,卻和暖如春陵霉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背伍绳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工踊挠, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人冲杀。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓效床,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親权谁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子剩檀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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