redux篇

# hello

傳統(tǒng)的狀態(tài)管理

在jquery時(shí)代槽奕,往往把全局變量定義在代碼的最前面,使每一個(gè)頁(yè)面都能使用他

<body>
    <div>
        <button id="add">+ 1</button>
        <span id="number"></span>
        <button id="minus">- 1</button>
    </div>

    <script src='https://cdn.bootcss.com/jquery/3.4.1/jquery.js'></script>
    <script>
        $(function () {

            // 變量 注釋1
            const myState = { number: 1 }

            // 增加
            $("#add").click(() => {
                myState.number++; // 注釋2
                render();
            })

            // 減少
            $("#minus").click(() => {
                myState.number--; // 注釋2
                render();
            })

            // 渲染DOM
            const render = () => $("#number").html(myState.number);

            render();
        });
    </script>
</body>

在 React 中撒轮,我們把變量(注釋1)稱(chēng)作狀態(tài)(state)

而通過(guò) React 基礎(chǔ)的學(xué)習(xí)我們發(fā)現(xiàn), React 的狀態(tài)都是在組件內(nèi)部(局部),當(dāng)組件嵌套復(fù)雜時(shí)昙篙,很難管理狀態(tài),也就是說(shuō)诱咏,很難實(shí)現(xiàn)全局變量

這個(gè)時(shí)候苔可,市場(chǎng)上出現(xiàn)了很多優(yōu)秀的解決方案,比如Flux袋狞,Redux焚辅,React-Redux删咱,useContext+useReduce酣溃,dva等

Redux 是基于 Flux 的改良版,不僅僅服務(wù)于React昵时,任何前端框架都可以使用

Redux 思路

把狀態(tài)(上述代碼注釋1)早处,操作(上述代碼注釋2)融合成一個(gè)容器湾蔓,通過(guò)視圖分發(fā)指令去更新?tīng)顟B(tài),并通過(guò)訂閱更新視圖

狀態(tài):State

操作:Reduce

容器:Store

分發(fā):dispatch

指令:action

訂閱:subscribe

hello Redux

Redux 通過(guò) createStore 創(chuàng)建一個(gè)容器砌梆,createStore 需要參數(shù) Reduce 默责, Reduce 有兩個(gè)參數(shù),狀態(tài)和指令

Reduce 是一個(gè)純函數(shù)咸包,只能回返新?tīng)顟B(tài)桃序,不更新原狀態(tài)

dispatch 分發(fā)的必須是一個(gè)對(duì)象

分發(fā)后,會(huì)調(diào)用 Reduce烂瘫,而且會(huì)把 dispatch 的參數(shù)會(huì)作為 Reduce 的第二個(gè)參數(shù)

<body>
    <div>
        <button id="add">+ 1</button>
        <span id="number"></span>
        <button id="minus">- 1</button>
    </div>

    <script src='https://cdn.bootcss.com/jquery/3.4.1/jquery.js'></script>
    <script src="./redux.js"></script>
    <script>
        $(function () {

            // 狀態(tài)
            const myState = { number: 1 }

            // 操作
            const Reduce = (state = myState, action) => {
                if (action.type == "增加") return { ...state, number: state.number + 1 }
                else if (action.type == "減少") return { ...state, number: state.number - 1 }
                else return state;
            }

            // 容器
            const Store = Redux.createStore(Reduce);

            // 訂閱
            Store.subscribe(() => render());

            // 增加
            $("#add").click(() => Store.dispatch({ type: "增加" }));

            // 減少
            $("#minus").click(() => Store.dispatch({ type: "減少" }));

            // 渲染DOM
            const render = () => $("#number").html(Store.getState().number);

            render();
        });
    </script>
</body>

指令重寫(xiě)

指令可以帶一個(gè)參數(shù)媒熊,約定俗稱(chēng)payload,而且type我們把它改成英文名顯得更專(zhuān)業(yè)些

// 操作
const Reduce = (state = myState, action) => {
    if (action.type == "add") return { ...state, number: action.payload }
    else if (action.type == "minus") return { ...state, number: action.payload }
    else return state;
}

// 增加
$("#add").click(() => Store.dispatch({ type: "add", payload: Store.getState().number + 1 }));

// 減少
$("#minus").click(() => Store.dispatch({ type: "minus", payload: Store.getState().number - 1 }));

可以所有的指令用一個(gè)變量存儲(chǔ)(大寫(xiě)表示常量),那么再使用的過(guò)程中芦鳍,不容易出錯(cuò)嚷往,還可以復(fù)用

// 所有指令
const Actions = {
    ADD: "add",
    MINUS: "minus"
}

// 操作
const Reduce = (state = myState, action) => {
    if (action.type == Actions.ADD) return { ...state, number: action.payload }
    else if (action.type == Actions.MINUS) return { ...state, number: action.payload }
    else return state;
}

// 增加
$("#add").click(() => Store.dispatch({ type: Actions.ADD, payload: Store.getState().number + 1 }));

// 減少
$("#minus").click(() => Store.dispatch({ type: Actions.MINUS, payload: Store.getState().number - 1 }));

為了更加貼合管網(wǎng)(深層裝X),我們可以在 dispatch 一個(gè)由 createAction 生成的指令

// 所有指令
const Actions = {
    ADD: "add",
    MINUS: "minus"
}

// 生成指令
const createAction = {
    ADD(payload) {
        return { type: Actions.ADD, payload }
    },
    MINUS(payload) {
        return { type: Actions.MINUS, payload }
    }
}

// 操作
const Reduce = (state = myState, action) => {
    if (action.type == Actions.ADD) return { ...state, number: action.payload }
    else if (action.type == Actions.MINUS) return { ...state, number: action.payload }
    else return state;
}

// 增加
$("#add").click(() => Store.dispatch(createAction.ADD(Store.getState().number + 1)));

// 減少
$("#minus").click(() => Store.dispatch(createAction.ADD(Store.getState().number - 1)));

再把 Reduce 的if判斷改為更為高大上的 switch

OK 怜校,全部改完后的代碼如下

<body>
    <div>
        <button id="add">+ 1</button>
        <span id="number"></span>
        <button id="minus">- 1</button>
    </div>

    <script src='https://cdn.bootcss.com/jquery/3.4.1/jquery.js'></script>
    <script src="./redux.js"></script>
    <script>
        $(function () {

            // 狀態(tài)
            const myState = { number: 1 }

            // 所有指令
            const Actions = {
                ADD: "add",
                MINUS: "minus"
            }

            // 生成指令
            const createAction = {
                ADD(payload) {
                    return { type: Actions.ADD, payload }
                },
                MINUS(payload) {
                    return { type: Actions.MINUS, payload }
                }
            }

            // 操作
            const Reduce = (state = myState, action) => {
                switch (action.type) {
                    case Actions.ADD:
                        return { ...state, number: action.payload };
                    case Actions.MINUS:
                        return { ...state, number: action.payload };
                    default:
                        return state;
                }
            }

            // 容器
            const Store = Redux.createStore(Reduce);

            // 訂閱
            Store.subscribe(() => render());

            // 增加
            $("#add").click(() => Store.dispatch(createAction.ADD(Store.getState().number + 1)));

            // 減少
            $("#minus").click(() => Store.dispatch(createAction.ADD(Store.getState().number - 1)));

            // 渲染DOM
            const render = () => $("#number").html(Store.getState().number);

            render();
        });
    </script>
</body>

再讀 Redux

Redux 是 JavaScript 狀態(tài)容器间影,提供可預(yù)測(cè)化的狀態(tài)管理

我們把這句話分解一下:

狀態(tài)(State)

容器(Store)

可預(yù)測(cè)(Action)

狀態(tài)管理(Reduce)

# React 配合 Redux

安裝Redux

yarn add Redux

容器

import { createStore } from "redux"

// 狀態(tài)
const myState = { number: 1 }

// 所有指令
const Actions = {
    ADD: "add",
    MINUS: "minus"
}

// 生成指令
const createAction = {
    ADD(payload) {
        return { type: Actions.ADD, payload }
    },
    MINUS(payload) {
        return { type: Actions.MINUS, payload }
    }
}

// 操作
const Reduce = (state = myState, action) => {
    switch (action.type) {
        case Actions.ADD:
            return { ...state, number: action.payload };
        case Actions.MINUS:
            return { ...state, number: action.payload };
        default:
            return state;
    }
}

// 容器
const Store = createStore(Reduce);

export {
    createAction, Store
}

App組件

import React, { useState } from 'react';
import { Store, createAction } from "./Store/index"

function App() {

  const [number, setNumber] = useState(Store.getState().number);

  // 訂閱狀態(tài)更新
  Store.subscribe(() => setNumber(Store.getState().number));

  const changeNumber = (props) => {
    // 分發(fā)指令
    if (props == `add`) Store.dispatch(createAction.ADD(number + 1));
    else if (props == `minus`) Store.dispatch(createAction.MINUS(number - 1));
  }

  return (
    <div>
      <button onClick={() => changeNumber(`add`)}>+ 1</button>
      <span>{number}</span>
      <button onClick={() => changeNumber(`minus`)}>- 1</button>
    </div>
  )
}

export default App;

# 圖解 React + Redux

圖一

download.png

React 某個(gè)組件分發(fā)(Dispatch)一個(gè)指令更新Store

容器訂閱(Subscribe)狀態(tài)(State)更新后,重新渲染組件

圖二

download (1).png

視圖(View)把指令(Actions)分發(fā)(Dispatch)給容器(Store)

容器根據(jù)分發(fā)的指令可預(yù)測(cè)的管理(Redux)狀態(tài)(State)

容器偵聽(tīng)(Subscibe)了狀態(tài)(State)的變化茄茁,更新了視圖(View)

# 取消訂閱

每次在組件銷(xiāo)毀的時(shí)候魂贬,必須取消訂閱避免內(nèi)存泄露

其實(shí)在組件銷(xiāo)毀時(shí),不僅僅要取消訂閱裙顽,還要清空定時(shí)器付燥,DOM偵聽(tīng)等副作用

import React, { useState, useEffect } from 'react';
import { Store, createAction } from "./Store/index"

function App() {

  const [number, setNumber] = useState(Store.getState().number);

  // 訂閱狀態(tài)更新
  const sub = Store.subscribe(() => setNumber(Store.getState().number));

  useEffect(() => {
    return () => {
      sub();
    }
  });

  const changeNumber = (props) => {
    // 分發(fā)指令
    if (props == `add`) Store.dispatch(createAction.ADD(number + 1));
    else if (props == `minus`) Store.dispatch(createAction.MINUS(number - 1));
  }

  return (
    <div>
      <button onClick={() => changeNumber(`add`)}>+ 1</button>
      <span>{number}</span>
      <button onClick={() => changeNumber(`minus`)}>- 1</button>
    </div>
  )
}

export default App;

# reduce

介紹

當(dāng)頁(yè)面非常龐大的時(shí)候,如果狀態(tài)管理都寫(xiě)在一起非常不好維護(hù)愈犹,redux 有一個(gè) combineReducers 可以把狀態(tài)管理拆成小塊键科,從而使開(kāi)發(fā)維護(hù)更加方便

快速 demo

Store.js

import { createStore, combineReducers } from "redux"

// 狀態(tài)
const NumberState = { number: 1 }
const UserState = [{ name: "張三", age: 12 }]

// 所有指令
const NumberActions = {
    ADD: "add",
    MINUS: "minus"
}
const UserActions = {
    INIT: "init",
    ADD: "add",
    UPDATE: "update"
}

// 生成指令
const createNumberAction = {
    ADD(payload) {
        return { type: NumberActions.ADD, payload }
    },
    MINUS(payload) {
        return { type: NumberActions.MINUS, payload }
    }
}

const createUserAction = {
    INIT(payload) {
        return { type: UserActions.INIT, payload }
    },
    ADD(payload) {
        return { type: UserActions.ADD, payload }
    },
    UPDATE(payload) {
        return { type: UserActions.UPDATE, payload }
    }
}

// 操作
const NumberReduce = (state = NumberState, action) => {
    switch (action.type) {
        case NumberActions.ADD:
            return { ...state, number: action.payload };
        case NumberActions.MINUS:
            return { ...state, number: action.payload };
        default:
            return state;
    }
}

const UserReduce = (state = UserState, action) => {
    switch (action.type) {
        case NumberActions.ADD:
            return { ...state, number: action.payload };
        case NumberActions.MINUS:
            return { ...state, number: action.payload };
        default:
            return state;
    }
}

const reduce = combineReducers({
    Num: NumberReduce,
    User: UserReduce
});

// 容器
const Store = createStore(reduce);

export {
    createNumberAction, Store
}

action , createAction漩怎, Reduce 都要寫(xiě)兩份勋颖,最后合成一份Store,并在 combineReducers 時(shí)勋锤,給不同的 redux 加上名稱(chēng)饭玲,方便 Store 調(diào)用

APP.js

import React, { useState, useEffect } from 'react';
import { Store, createNumberAction } from "./Store/index"

function App() {

  const [number, setNumber] = useState(Store.getState().Num.number);

  // 訂閱狀態(tài)更新
  const sub = Store.subscribe(() => setNumber(Store.getState().Num.number));

  useEffect(() => {
    return () => {
      sub();
    }
  });

  const changeNumber = (props) => {
    // 分發(fā)指令
    if (props == `add`) Store.dispatch(createNumberAction.ADD(number + 1));
    else if (props == `minus`) Store.dispatch(createNumberAction.MINUS(number - 1));
  }

  return (
    <div>
      <button onClick={() => changeNumber(`add`)}>+ 1</button>
      <span>{number}</span>
      <button onClick={() => changeNumber(`minus`)}>- 1</button>
    </div>
  )
}

export default App;

調(diào)用的時(shí)候,需要用 Store 調(diào)用 combineReducers 合并時(shí)取的別名

Redux 文件拆分

可以把不同的Redux拆分文件單獨(dú)提出

├── Store                   # 狀態(tài)管理容器
│   ├── numberReduce.js     # 數(shù)字reduce
│   ├── userReduce.js       # 用戶(hù)reduce
│   └── index.js
├── App.js                  # 根組件

./Store/numberReduce.js

// 狀態(tài)
const NumberState = { number: 1 }

// 所有指令
const NumberActions = {
    ADD: "add",
    MINUS: "minus"
}

// 生成指令
const createNumberAction = {
    ADD(payload) {
        return { type: NumberActions.ADD, payload }
    },
    MINUS(payload) {
        return { type: NumberActions.MINUS, payload }
    }
}

// 操作
const NumberReduce = (state = NumberState, action) => {
    switch (action.type) {
        case NumberActions.ADD:
            return { ...state, number: action.payload };
        case NumberActions.MINUS:
            return { ...state, number: action.payload };
        default:
            return state;
    }
}

export { createNumberAction, NumberReduce }
export default NumberReduce;

./Store/userReduce.js

// 狀態(tài)
const UserState = [{ name: "張三", age: 12 }]

// 所有指令
const UserActions = {
    INIT: "init",
    ADD: "add",
    UPDATE: "update"
}

// 生成指令
const createUserAction = {
    INIT(payload) {
        return { type: UserActions.INIT, payload }
    },
    ADD(payload) {
        return { type: UserActions.ADD, payload }
    },
    UPDATE(payload) {
        return { type: UserActions.UPDATE, payload }
    }
}

// 操作
const UserReduce = (state = UserState, action) => {
    return UserState;
}
export { createUserAction, UserReduce }
export default UserReduce;

./Store/index.js

import { createStore, combineReducers } from "redux"
import NumberReduce from "./numberReduce"
import UserReduce from "./userReduce"

// 合并
const reduce = combineReducers({
    Num: NumberReduce,
    User: UserReduce
});

// 容器
export default createStore(reduce);

./App.js

import React, { useState, useEffect } from 'react';
import Store from "./Store/index"
import { createNumberAction } from "./Store/numberReduce"

function App() {

  const [number, setNumber] = useState(Store.getState().Num.number);

  // 訂閱狀態(tài)更新
  const sub = Store.subscribe(() => setNumber(Store.getState().Num.number));

  useEffect(() => {
    return () => {
      sub();
    }
  });

  const changeNumber = (props) => {
    // 分發(fā)指令
    if (props == `add`) Store.dispatch(createNumberAction.ADD(number + 1));
    else if (props == `minus`) Store.dispatch(createNumberAction.MINUS(number - 1));
  }

  return (
    <div>
      <button onClick={() => changeNumber(`add`)}>+ 1</button>
      <span>{number}</span>
      <button onClick={() => changeNumber(`minus`)}>- 1</button>
    </div>
  )
}

export default App;

這是以功能模塊拆分叁执,還可以以 Store 拆分

├── Store                   # 狀態(tài)管理容器
│   ├── action
│   │   ├── numberAction
│   │   ├── userAction
│   ├── reduce
│   │   ├── numberReduce
│   │   ├── userReduce
│   ├── state
│   │   ├── numberState
│   │   ├── userState
│   └── index.js
├── App.js                  # 根組件

# 配合請(qǐng)求更新?tīng)顟B(tài)

用 json-server 模擬數(shù)據(jù)

安裝

$ npm install -g json-server

數(shù)據(jù)模擬

{
    "User": [
        {
            "id": "001",
            "name": "Sherry",
            "age": 24
        },
        {
            "id": "002",
            "name": "Addy",
            "age": 24
        },
        {
            "id": "003",
            "name": "Jack",
            "age": 24
        },
        {
            "id": "004",
            "name": "Rebeca",
            "age": 24
        }
    ]
}

啟動(dòng)服務(wù)

$ json-server --watch --port 3001 db.json

請(qǐng)求數(shù)據(jù)更新?tīng)顟B(tài)

為了方便測(cè)試茄厘,把 numberReducer 的功能去掉

App.js

import React, { useState, useEffect } from 'react';
import Store from "./Store/index"
import axios from "axios"
import { createUserAction } from "./Store/userReduce"

function App() {

  const [user, setUser] = useState(Store.getState().User);

  const sub = Store.subscribe(() => setUser(Store.getState().User));

  useEffect(() => {

    axios.get(`http://localhost:3001/User`).then(res => {
      Store.dispatch(createUserAction.INIT(res.data));
    })

    return () => {
      sub();
    }
  }, []);

  return (
    <>
      {user.map(item => <p key={item.id}>{item.name} --- {item.age}</p>)}
    </>
  )
}

export default App;

userReduce 簡(jiǎn)化成一個(gè)指令

// 所有指令
const UserActions = {
    INIT: "init"
}

// 生成指令
const createUserAction = {
    INIT(payload) {
        return { type: UserActions.INIT, payload }
    }
}

// 操作
const UserReduce = (state = [], action) => {
    if (action.type == UserActions.INIT) {
        return action.payload;
    }
    return state;
}
export { createUserAction, UserReduce }
export default UserReduce;

此時(shí)就能配合請(qǐng)求更新?tīng)顟B(tài)了。如果需要指令異步執(zhí)行谈宛,可以使用redux中間件

中間件

redux 中間件是在 action 和 reduce環(huán)節(jié)中次哈,添加的功能

使用例子

import { createStore, combineReducers, applyMiddleware } from "redux"
import NumberReduce from "./numberReduce"
import UserReduce from "./userReduce"
import thunk from "redux-thunk"

// 合并
const reduce = combineReducers({
    Num: NumberReduce,
    User: UserReduce
});

// 容器
export default createStore(reduce, applyMiddleware(thunk));

# redux-thunk

介紹

redux-thunk 屬于 redux 的中間件,作用是可以讓 dispatch 返回的是一個(gè)函數(shù)吆录,那么就可以把異步的寫(xiě)法搬到 action 中

App.js

import React, { useState, useEffect } from 'react';
import Store from "./Store/index"
import axios from "axios"
import { createUserAction } from "./Store/userReduce"

function App() {

  const [user, setUser] = useState(Store.getState().User);

  const sub = Store.subscribe(() => setUser(Store.getState().User));

  useEffect(() => {

    Store.dispatch(createUserAction.ASYNCINIT());

    return () => {
      sub();
    }
  }, []);

  return (
    <>
      {user.map(item => <p key={item.id}>{item.name} --- {item.age}</p>)}
    </>
  )
}

export default App;

Reduce.js

import axios from "axios"

// 所有指令
const UserActions = {
    ASYNCINIT: "init"
}

// 生成指令
const createUserAction = {
    ASYNCINIT() {
        return (dispatch, getState) => {
            axios.get(`http://localhost:3001/User`).then(res => {
                dispatch({ type: UserActions.ASYNCINIT, payload: res.data });
            })
        }
    }
}

// 操作
const UserReduce = (state = [], action) => {
    if (action.type == UserActions.ASYNCINIT) {
        return action.payload;
    }
    return state;
}
export { createUserAction, UserReduce }
export default UserReduce;

index.js

import { createStore, combineReducers, applyMiddleware } from "redux"
import NumberReduce from "./numberReduce"
import UserReduce from "./userReduce"
import thunk from "redux-thunk"

// 合并
const reduce = combineReducers({
    Num: NumberReduce,
    User: UserReduce
});

// 容器
export default createStore(reduce, applyMiddleware(thunk));

# redux-saga

介紹

redux-saga 和 redux-thunk 一樣窑滞,都是 redux 中,名氣非常高的中間件

dva 還是基于 redux-saga 的一個(gè)數(shù)據(jù)流方案

思路

容器分發(fā)一個(gè)指令恢筝,用 redux-saga 去偵聽(tīng)(其實(shí)reduce也偵聽(tīng)到了哀卫,只不過(guò)不處理事件),偵聽(tīng)到后滋恬,做一系列的異步或同步操作聊训,再用put發(fā)送一個(gè)指令抱究,再由reduce偵聽(tīng)并更新?tīng)顟B(tài)

注意:redux-saga 發(fā)送的指令不能和偵聽(tīng)的指令相同恢氯,否則會(huì)一直執(zhí)行

App.js

import React, { useState, useEffect } from 'react';
import Store from "./Store/index"
import { createUserAction } from "./Store/userReduce"

function App() {

  const [user, setUser] = useState(Store.getState().User);
  const sub = Store.subscribe(() => setUser(Store.getState().User));

  useEffect(() => {
    Store.dispatch(createUserAction.ASYNCINIT);

    return () => {
      sub();
    }
  }, []);

  return (
    <>
      {user.map(item => <p key={item.id}>{item.name} --- {item.age}</p>)}
    </>
  )
}

export default App;

userReduce

// 所有指令
const UserActions = {
    ASYNCINIT: "asyncinit",
    INIT: "init"
}

// 生成指令
const createUserAction = {
    ASYNCINIT: {
        type: UserActions.ASYNCINIT
    },
    INIT(payload) {
        return {
            type: UserActions.INIT,
            payload: payload
        }
    }
}

// 操作
const UserReduce = (state = [], action) => {
    console.log(action);

    if (action.type == UserActions.INIT) {
        return action.payload || state;
    }
    return state;
}

export { createUserAction, UserReduce, UserActions }
export default UserReduce;

Store

import { createStore, combineReducers, applyMiddleware } from "redux"
import NumberReduce from "./numberReduce"
import UserReduce from "./userReduce"
import reduxSaga from "redux-saga"
import sagas from "./sagas"

const sage = reduxSaga();

// 合并
const reduce = combineReducers({
    Num: NumberReduce,
    User: UserReduce
});

// 容器
export default createStore(reduce, applyMiddleware(sage));

sage.run(sagas);

sagas

import { takeEvery, put } from "redux-saga/effects"
import { UserActions, createUserAction } from "./userReduce"
import axios from "axios"

function* mySaga() {
    yield takeEvery(UserActions.ASYNCINIT, getList);
}

function* getList() {
    const res = yield axios.get("http://localhost:3001/User");
    yield put(createUserAction.INIT(res.data));
}

export default mySaga;

# redux-devtools-extension 調(diào)試工具

chrome 插件

地址: https://chrome.google.com/webstore/detail/redux-devtools/lmhkpmbekcpmknklioeibfkpmmfibljd

配置

$ npm install --save-dev redux-devtools-extension

配置

import { createStore, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension';

const store = createStore(reducer, composeWithDevTools(
  applyMiddleware(...middleware),
  // other store enhancers if any
));

上一篇:React Hook篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子勋拟,更是在濱河造成了極大的恐慌勋磕,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件敢靡,死亡現(xiàn)場(chǎng)離奇詭異挂滓,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)啸胧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)赶站,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人纺念,你說(shuō)我怎么就攤上這事贝椿。” “怎么了陷谱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵烙博,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我烟逊,道長(zhǎng)渣窜,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任宪躯,我火速辦了婚禮乔宿,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘眷唉。我一直安慰自己予颤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布冬阳。 她就那樣靜靜地躺著蛤虐,像睡著了一般。 火紅的嫁衣襯著肌膚如雪肝陪。 梳的紋絲不亂的頭發(fā)上驳庭,一...
    開(kāi)封第一講書(shū)人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音氯窍,去河邊找鬼饲常。 笑死,一個(gè)胖子當(dāng)著我的面吹牛狼讨,可吹牛的內(nèi)容都是我干的贝淤。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼政供,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼播聪!你這毒婦竟也來(lái)了朽基?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤离陶,失蹤者是張志新(化名)和其女友劉穎稼虎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體招刨,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡霎俩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沉眶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片打却。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖谎倔,靈堂內(nèi)的尸體忽然破棺而出学密,到底是詐尸還是另有隱情,我是刑警寧澤传藏,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布腻暮,位于F島的核電站,受9級(jí)特大地震影響毯侦,放射性物質(zhì)發(fā)生泄漏哭靖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一侈离、第九天 我趴在偏房一處隱蔽的房頂上張望试幽。 院中可真熱鬧,春花似錦卦碾、人聲如沸铺坞。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)济榨。三九已至,卻和暖如春绿映,著一層夾襖步出監(jiān)牢的瞬間擒滑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工叉弦, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丐一,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓淹冰,卻偏偏與公主長(zhǎng)得像库车,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子樱拴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359