React Hooks

React Hooks

Hook是React v16.8的新特性攻柠,可以用函數(shù)的形式代替原來的繼承類的形式,可以在不編寫class的情況下使用state以及其他React特性

React 設(shè)計原理

  • React認(rèn)為崎溃,UI視圖是數(shù)據(jù)的一種視覺映射,UI = F(Data),這里的F主要負(fù)責(zé)對輸入數(shù)據(jù)進(jìn)行加工另玖,對數(shù)據(jù)變更做出相應(yīng)
  • 公式里的F在React里抽象成組件,React是以組件為粒度編排應(yīng)用的表伦,組件是代碼復(fù)用的最小單元
  • 在設(shè)計上谦去,React采用props屬性來接收外部數(shù)據(jù),使用state屬性來管理組件自身產(chǎn)生的數(shù)據(jù)蹦哼,而為了實現(xiàn)(運行時)對數(shù)據(jù)變更做出相應(yīng)需要鳄哭,React采用基于類的組件設(shè)計
  • 除此之外,React認(rèn)為組件是有生命周期的纲熏,因此提供了一系列API供開發(fā)者使用

我們所熟悉的React組件長這樣

import React, { Component } from "react";
// React基于Class設(shè)計組件
export default class Button extends Component {
    constructor() {
        super();
        // 組件自身數(shù)據(jù)
        this.state = { buttonText: "Click me, please" };
        this.handleClick = this.handleClick.bind(this);
    }
    // 響應(yīng)數(shù)據(jù)變更
    handleClick() {
        this.setState({ buttonText: "Thanks, been clicked!" });
    }
    // 編排數(shù)據(jù)呈現(xiàn)UI
    render() {
        const { buttonText } = this.state;
        return <button onClick={this.handleClick}>{buttonText}</button>;
    }
}

組件類的缺點

上面實例代碼只是一個按鈕組件妆丘,但是可以看到,它的代碼已經(jīng)很重了局劲。真實的React App由多個類按照層級勺拣,一層層構(gòu)成,復(fù)雜度成倍增長鱼填。再加入 Redux + React Router药有,就變得更復(fù)雜

很可能隨便一個組件最后export出去就是醬紫的:

export default withStyle(style)(connect(/*something*/)(withRouter(MyComponent)))

一個4層嵌套HOC,嵌套地獄

同時剔氏,如果你的組件內(nèi)事件多塑猖,那么你的constructor就是醬紫的

class MyComponent extends React.Component {
  constructor() {
    // initiallize
    this.handler1 = this.handler1.bind(this)
    this.handler2 = this.handler2.bind(this)
    this.handler3 = this.handler3.bind(this)
    this.handler4 = this.handler4.bind(this)
    this.handler5 = this.handler5.bind(this)
    // ...more
  }
}

而Function Component編譯后就是一個普通的function,function對js引擎是友好的谈跛,而Class Component在React內(nèi)部是當(dāng)做Javascript Function類來處理的羊苟,代碼很難被壓縮,比如方法名稱

還有this啦感憾,稍微不注意就會出現(xiàn)因this指向報錯的問題等蜡励。。阻桅。

總結(jié)一下就是:

  • 很難復(fù)用邏輯凉倚,會導(dǎo)致組件樹層級很深
  • 會產(chǎn)生巨大的組件(很多代碼必須寫在類里面)
  • 類組件很難理解,比如方法需要bind嫂沉,this的指向不明確
  • 編譯size稽寒,性能問題

Hooks

State Hook

Hook是什么?
可以先通過一個例子來看看趟章,在class中杏糙,我們通過在構(gòu)造函數(shù)中設(shè)置this.state初始化組件的state:

this.state = {
    n: 0
}

而在函數(shù)組件中慎王,我們沒有this,所以我們不能分配或讀取this.state宏侍,但是可以在組件中調(diào)用useStateHook

import React, {useState} from 'react';
function xxx() {
    const [n, setN] = useState(0);
}

在上面代碼中赖淤,useState就是Hook

Hook是一個特殊的函數(shù),它可以讓你“鉤入”React的特性谅河。例如useState是允許你在React函數(shù)組件中添加state的Hook咱旱。
如果你在編寫函數(shù)組件并意識到需要向其添加一些state,以前的做法是必須將其轉(zhuǎn)化為Class”了#現(xiàn)在你可以在現(xiàn)有的函數(shù)組件中使用Hook
讓函數(shù)組件自身具備狀態(tài)處理能力吐限,且自身能夠通過某種機(jī)制觸發(fā)狀態(tài)的變更并引起re-render,這種機(jī)制就是Hooks

走進(jìn)useState

示例代碼:

import React, { useState } from 'react';

function App() {
    // 聲明一個叫 "n" 的 state 變量
    // useState接收一個參數(shù)作為初始值
    // useState返回一個數(shù)組褂始,[state, setState]
    const [n, setN] = useState(0);

    return (
        <div>
        {/* 讀取n毯盈,等同于this.state.n */}
        <p>{n}</p>
        {/* 通過setN更新n,等同于this.setN(n: this.state.n + 1) */}
        <button onClick={() => setN(n + 1)}>
            +1
        </button>
        </div>
    );
}

運行一下(代碼1

  1. 首次渲染 render <App />
  2. 調(diào)用App函數(shù)病袄,得到虛擬DOM對象,創(chuàng)建真實DOM
  3. 點擊buttno調(diào)用setN(n + 1)赘阀,因為要更新頁面的n益缠,所以再次render<App />
  4. 重復(fù)第二步,從控制臺打印看出每次執(zhí)行setN都會觸發(fā)App函數(shù)運行基公,得到一個新的虛擬DOM幅慌,DOM Diff更新真實DOM

那么問題來了,首次運行App函數(shù)和setN時都調(diào)用了App轰豆,兩次運行useState是一樣的嗎胰伍?setN改變n的值了嗎?為什么得到了不一樣的n酸休,useState的時候做了什么骂租?

分析:

  • setN
    • setN一定會修改數(shù)據(jù)x,將n+1存入x
    • setN一定會觸發(fā)<App />重新渲染(re-render)
  • useState
    • useState肯定會從x讀取n的最新值
  • x
    • 每個組件都有自己的數(shù)據(jù)x斑司,我們將其命名為state

嘗試實現(xiàn)React.useState(代碼2

// 和useState一樣渗饮,myUseState接收一個初始值,返回state和setState方法
const myUseState = initialValue => {
    let state = initialValue
    const setState = newValue => {
        state = newValue
        // 重新渲染
        render()
    }
    return [state, setState]
}

const render = () => {
    // 雞賊暴力渲染法
    ReactDOM.render(<App />, rootElement)
}

function App() {
    const [n, setN] = myUseState(0)
    ...
}

點擊button宿刮,n沒有任何變化
原來每次state都變成了初始值0互站,因為myUseState會將state重置
我們需要一個不會被myUseState重置的變量,那么這個變量只要聲明在myUseState外面即可

let _state;
const myUseState = initialValue => {
    // 如果state是undefined僵缺,則賦給初始值胡桃,否則就賦值為保存在外面的_state
    _state = _state === undefined ? initialValue : _state;
    const setState = newValue => {
        _state = newValue;
        render();
    };
    return [_state, setState];
};

還有問題,如果一個組件有倆state咋整磕潮?由于所有數(shù)據(jù)都放在_state翠胰,產(chǎn)生沖突:

function App() {
    const [n, setN] = myUseState(0)
    const [m, setM] = myUseState(0)
    ...
}

解決:

  • 把_state做成對象
    • 不可行容贝,沒有key,useState(0)只傳入了一個參數(shù)0亡容,并不知道是n還是m
  • 把_state做成數(shù)組
    • 可行嗤疯,_state = [0, 0]
let _state = [];
let index = 0;
const myUseState = (initialValue) => {
    const currentIndex = index;
    _state[currentIndex] = _state[currentIndex] === undefined ? initialValue : _state[currentIndex];
    const setState = (newValue) => {
        _state[currentIndex] = newValue;
        render();
    };
    index += 1;
    return [_state[currentIndex], setState];
};

const render = () => {
    // 重新渲染要重置index
    index = 0;
    ReactDOM.render(<App />, rootElement);
};

解決了存在多個state的情況,但是還有問題闺兢,就是useState調(diào)用順序必須一致茂缚!

  • 如果第一次渲染時n是第一個,m是第二個屋谭,k是第三個
  • 則第二次渲染時必須保證順序一致脚囊,因為數(shù)組根據(jù)調(diào)用順序存儲值
  • re-render時會從第一行代碼開始重新執(zhí)行整個組件
  • 所以React不允許出現(xiàn)如下代碼

React Hook "useState" is called conditionally. React Hooks must be called in the exact same order in every component render.

只在最頂層使用 Hook

最后一個問題:
App用了_state和index,那其他組件用什么桐磁?放在全局作用域重名怎么解決悔耘?

運行App后,React會維護(hù)一個虛擬DOM樹我擂,每個節(jié)點都有一個虛擬DOM對象(Fiber)衬以,將_state,index存儲在對象上

額外擴(kuò)展一下Fiber對象校摩,它的數(shù)據(jù)結(jié)構(gòu)如下:

function FiberNode(
    tag: WorkTag,
    pendingProps: mixed,
    key: null | string,
    mode: TypeOfMode,
    ) {
    // Instance 實例
    this.tag = tag;
    this.key = key;
    // JSX翻譯過來之后是React.createElement看峻,他最終返回的是一個ReactElement對象
    // 就是ReactElement的`?typeof`
    this.elementType = null;
    // 就是ReactElement的type,他的值就是<MyClassComponent />這個class衙吩,不是實例互妓,實例是在render過程中創(chuàng)建
    this.type = null;
    this.stateNode = null;

    // Fiber
    this.return = null;
    this.child = null;
    this.sibling = null;
    this.index = 0;

    this.ref = null;

    this.pendingProps = pendingProps;
    this.memoizedProps = null;
    this.updateQueue = null;
    // 用來存儲state
    // 記錄useState應(yīng)該返回的結(jié)果
    this.memoizedState = null;
    this.firstContextDependency = null;

    // ...others
}

總結(jié):

  • 每個函數(shù)組件對應(yīng)一個React節(jié)點(FiberNode)
  • 每個節(jié)點保存著_state(memorizedState)和index(實際是鏈表)
  • useState會讀取對應(yīng)節(jié)點的state[index]
  • index是由useState的調(diào)用順序決定
  • setState會修改_state,并觸發(fā)更新

搞清楚useState干了啥以后坤塞,回過頭再看setN改變n了嗎冯勉,為什么得到了不一樣的n代碼3

  • 先+1,后log => 1
  • 先log摹芙,后+1 => 0
  • 為什么log出了舊數(shù)據(jù)

分析:

  • 先點擊log灼狰,log(0)三秒后執(zhí)行,此時n0瘫辩,n不會變
  • 再點擊+1伏嗜,此時調(diào)用的是一個新的函數(shù),生成了新的n伐厌,re-render
  • n=0n=1同時存在內(nèi)存中

結(jié)論:因為有多個n承绸,setN并不會改變n,React函數(shù)式編程決定了n的值不會被改變挣轨,只會被回收

注意事項:

  • 不可局部更新(代碼4
  • 地址要變:setState(obj)如果obj地址不變军熏,那么React就認(rèn)為數(shù)據(jù)沒有變化
  • useState接受函數(shù):函數(shù)返回初始state,且只執(zhí)行一次
  • setState接收函數(shù):setN(i => i + 1)卷扮,優(yōu)先使用這種形式

useReducer

React本身不提供狀態(tài)管理功能荡澎,通常需要使用外部庫均践,最常用的庫是Redux
Redux的核心概念是,將需要修改的state都存入到store里摩幔,發(fā)起一個action用來描述發(fā)生了什么彤委,用reducers描述action如何改變state,真正能改變store中數(shù)據(jù)的是store.dispatch API
Reducer是一個純函數(shù)或衡,只承擔(dān)計算 State 的功能焦影,函數(shù)的形式是(state, action) => newState
Action是消息的載體,只能被別人操作封断,自己不能進(jìn)行任何操作
useReducer()鉤子用來引入Reducer功能(代碼5

const [state, dispatch] = useReducer(reducer, initial)

上面是useReducer基本用法

  • 接受Reducer函數(shù)和一個初始值作為參數(shù)
  • 返回一個數(shù)組斯辰,數(shù)組[0]位是狀態(tài)當(dāng)前值,第[1]位是dispatch函數(shù)坡疼,用來發(fā)送action

似曾相識的感覺

const [n, setN] = useState(0)
//   n:讀
//   setN:寫

總的來說useReducer就是復(fù)雜版本的useState彬呻,那么什么時候使用useReducer,什么時候又使用useState呢柄瑰?
看一個代碼6
當(dāng)你需要維護(hù)多個state闸氮,那么為什么不用一個對象來維護(hù)呢,對象是可以合并的

需要注意的是教沾,由于Hooks可以提供狀態(tài)管理和Reducer函數(shù)湖苞,所以在這方面可以取代Redux。但是详囤,它沒法兒提供中間件(midddleware)和時間旅行(time travel),如果你需要這兩個功能镐作,還是要用Redux藏姐。

中間件原理:封裝改造store.dispatch,將其指向中間件该贾,以實現(xiàn)在dispatch和reducer之間處理action數(shù)據(jù)的邏輯羔杨,也可以將中間件看成是dispatch方法的封裝器

有沒有代替Redux的方法呢?

Reducer + Context

useContext

什么是上下文杨蛋?

  • 全局變量是全局的上下文
  • 上下文是局部的全局變量

使用方法:

// 創(chuàng)建上下文
const c = createContext(null)

function App() {
    const [n, setN] = useState(0)
    return (
        // 使用<c.Provider>圈定作用域
        <c.Provider value={n, setN}>
            <Father />
        </ c.Provider>
    )
}

function Father() {
    return (
        <div>我是爸爸
            <Son />
        </div>
    )
}

function Son() {
    // 在作用域中使用useContext(c)來獲取并使用上下文
    // 要注意這里useContext返回的是對象兜材,不是數(shù)組
    const {n, setN} = useContext(c)
    const onClick = () => {
        setN( i => i + 1)
    }
    return (
        <div>我是兒子,我可以拿到n:{n}
            <button onClick={onClick}>我也可以更新n</button>
        </div>
        
    )
}

注意事項:

  • 使用useContext時逞力,在一個模塊改變數(shù)據(jù)曙寡,另一個模塊是感知不到的
  • setN會重新渲染<App />,自上而下逐級通知更新寇荧,并不是響應(yīng)式举庶,因為響應(yīng)式是監(jiān)聽數(shù)據(jù)變化通知對應(yīng)組件進(jìn)行更新

useEffect

useEffect鉤子會在每次render后運行
React保證了每次運行useEffect的同時,DOM 都已經(jīng)更新完畢

應(yīng)用:

  • 作為componentDidMount使用揩抡,[]作第二個參數(shù)
  • 作為componentDidUpdate使用户侥,可指定依賴
  • 作為componentWillUnmount使用镀琉,通過return
  • 以上三種可同時存在
function App() {
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(i => i + 1)
    }

    const afterRender = useEffect;
    // componentDidMount
    useEffect(() => {
        console.log('第一次渲染之后執(zhí)行這句話')
    }, [])
    // componentDidUpdate
    useEffect(() => {
        console.log('每次次都會執(zhí)行這句話')
    })

    useEffect(() => {
        console.log('n變化就會執(zhí)行這句話,包含第一次')
    }, [n])
    // componentWillUnmount
    useEffect(() => {
        const id = setInterval(() => {
            console.log('每一秒都打印這句話')
        }, 1000)
        return () =>{
            // 如果組件多次渲染蕊唐,則在執(zhí)行下一個 effect 之前屋摔,上一個 effect 就已被清除
            console.log('當(dāng)組件要掛掉了,打印這句話')
            window.clearInterval(id)
        }
    }, [])
    return (
        <div>
            n: {n}
            <button onClick={onClick}>+1</button>
        </div>
    )
}

Hook 允許我們按照代碼的用途分離他們替梨,而不是像生命周期函數(shù)那樣
React將按照effect聲明的順序依次調(diào)用組件中的每一個effect

對應(yīng)的钓试,另一個effect鉤子,useLayoutEffect

  • useEffect在瀏覽器渲染之后執(zhí)行耙替,useLayoutEffect在渲染前執(zhí)行(代碼7
  • useLayoutEffect在渲染前執(zhí)行亚侠,使用它來讀取 DOM 布局并同步觸發(fā)重渲染
// 偽代碼
App() -> 執(zhí)行 -> VDOM -> DOM -> useLayoutEffect -> render -> useEffect

特點:

  • useLayoutEffect性能更好,但是會影響用戶看到頁面變化的時間(代碼7
  • useLayoutEffect總是比useEffect先執(zhí)行
  • useLayoutEffect里的任務(wù)最好是影響了layout
  • 還是推薦優(yōu)先使用useEffect(如果不涉及操作dom的操作)

為什么建議將修改DOM的操作放到useLayoutEffect里俗扇,而不是useEffect呢硝烂,是因為當(dāng)DOM被修改時,瀏覽器的線程處于被阻塞階段(js線程和瀏覽器線程互斥)铜幽,所以還沒有發(fā)生回流滞谢、重繪。由于內(nèi)存中的DOM已經(jīng)被修改除抛,通過useLayoutEffect可以拿到最新的DOM節(jié)點狮杨,并且在此時對DOM進(jìn)行樣式上的修改。這樣修改一次性渲染到屏幕到忽,依舊只有一次回流橄教、重繪的代價。

注意:
由于useEffect是在render之后執(zhí)行喘漏,瀏覽器完成布局和繪制后护蝶,不應(yīng)在函數(shù)中執(zhí)行阻塞瀏覽器更新屏幕的操作

useMemo

React默認(rèn)有多余的render(修改n,但是依賴m的組件卻自動刷新了)翩迈,如果props不變就沒有必要再執(zhí)行一次函數(shù)組件持灰,先從一個例子來理解memo(代碼8

這里有一個問題,如果給子組件一個方法负饲,即使prop沒有變化堤魁,子組件還是會每一次都執(zhí)行

const onClickChild = () => {}

<Child data={m} onClick={onClickChild} />

這是因為在App重新渲染時,生成了新的函數(shù)返十,就像一開始講的多個n的道理一樣妥泉,新舊函數(shù)雖然功能一樣,但是地址不一樣洞坑,這就導(dǎo)致props還是變化了

那么對于子組件的方法涛漂,如何重用?
使用useMemo鉤子(代碼9)

const onClickChild = useMemo(() => {
    return () => {
        console.log(m)
    }
}, [m])

特點:

  • useMemo第一個參數(shù)是() => value(value可以是函數(shù)、對象之類的),第二個參數(shù)是依賴數(shù)組[m]
  • 只有當(dāng)依賴變化時匈仗,才會重新計算新的value
  • 如果依賴沒有變化瓢剿,就重用之前的value
  • 這不就是vue中的computed嗎?

注意:

  • 如果你的value是個函數(shù)悠轩,那么你要寫成useMemo(() => x => console.log(x))
  • 這是一個返回函數(shù)的函數(shù)
  • 這么難用的話间狂,用用useCallback
// useMemo
const onClickChild = useMemo(() => {
    return () => {
        console.log(m)
    }
}, [m])

// useCallback
const onClickChild = useCallback(() => {
    console.log(m)
})

// 偽代碼
useCallback(x => log(x), [m]) 等價于 useMemo(() => x => log(x), [m])

useMemouseCallback作用完全一樣,語法糖而已

useRef

一直用到的這個例子火架,每點擊一下就會重新渲染一下App

function App() {
    console.log('App 執(zhí)行');
    const [n, setN] = useState(0)
    const onClick = () => {
        setN(i => i + 1)
    }

    return (
        <div>
            <button onClick={onClick}>update n {n}</button>
        </div>
    )
}

假如我要知道這個App執(zhí)行了多少次鉴象,我怎么記錄?
如果我需要一個值何鸡,在組件不斷render的時候也能夠保持不變怎么做纺弊?

function App() {
    // count的值通過useRef記錄了下來
    // 初始化
    const count = useRef(0)

    useEffect(() => {
        // 讀取 count.current
        count.current += 1
    })
}

同樣的,useRef也是通過它所對應(yīng)的fiberNode對象來保存

為什么需要current骡男?

  • 為了保證兩次useRef是同一個值淆游,只有引用才能做到
  • useRef存儲的實際上是一個對象{currnt: 0},對象對應(yīng)的是同一個地址(內(nèi)存)
  • 每次改變只是改變對象中的值隔盛,而不是改變對象犹菱,新舊組件必須引用同一個對象

講了useRef就不得不講講forwardRef

在函數(shù)組件中怎么使用ref,嘗試一下(代碼10

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

說明吮炕,props無法傳遞ref屬性
所以腊脱,函數(shù)組件用ref的話,需要用forwardRef包裝做一下轉(zhuǎn)發(fā)龙亲,才能拿到ref

自定義Hook

通過自定義Hook陕凹,可以將組件邏輯提取到可重用的函數(shù)中
自定義Hook是一個函數(shù),其名稱以 “use” 開頭(符合 Hook 的規(guī)則)鳄炉,函數(shù)內(nèi)部可以調(diào)用其他的Hook
每次使用自定義 Hook 時捆姜,其中的所有 state 和副作用都是完全隔離的(每次調(diào)用 Hook,它都會獲取獨立的 state)
代碼

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市浆兰,隨后出現(xiàn)的幾起案子磕仅,更是在濱河造成了極大的恐慌,老刑警劉巖簸呈,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件榕订,死亡現(xiàn)場離奇詭異,居然都是意外死亡蜕便,警方通過查閱死者的電腦和手機(jī)劫恒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人两嘴,你說我怎么就攤上這事丛楚。” “怎么了憔辫?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵趣些,是天一觀的道長。 經(jīng)常有香客問我贰您,道長坏平,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任锦亦,我火速辦了婚禮舶替,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘杠园。我一直安慰自己顾瞪,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布返劲。 她就那樣靜靜地躺著玲昧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪篮绿。 梳的紋絲不亂的頭發(fā)上孵延,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音亲配,去河邊找鬼尘应。 笑死,一個胖子當(dāng)著我的面吹牛吼虎,可吹牛的內(nèi)容都是我干的犬钢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼思灰,長吁一口氣:“原來是場噩夢啊……” “哼玷犹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起洒疚,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤歹颓,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后油湖,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體巍扛,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年乏德,在試婚紗的時候發(fā)現(xiàn)自己被綠了撤奸。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吠昭。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖胧瓜,靈堂內(nèi)的尸體忽然破棺而出矢棚,到底是詐尸還是另有隱情,我是刑警寧澤贷痪,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布幻妓,位于F島的核電站,受9級特大地震影響劫拢,放射性物質(zhì)發(fā)生泄漏肉津。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一舱沧、第九天 我趴在偏房一處隱蔽的房頂上張望妹沙。 院中可真熱鬧,春花似錦熟吏、人聲如沸距糖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽悍引。三九已至,卻和暖如春帽氓,著一層夾襖步出監(jiān)牢的瞬間趣斤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工黎休, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留浓领,地道東北人。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓势腮,卻偏偏與公主長得像联贩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子捎拯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

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