React + Redux 和 Redux 工具包

?? 什么是 Redux 以及狀態(tài)的定義

Redux 是一個用于跨組件或應(yīng)用程序范圍狀態(tài)的狀態(tài)管理系統(tǒng)。我們可以將狀態(tài)的定義分為三種主要類型:

Local State ??是屬于單個組件的狀態(tài),例如切換狀態(tài)。它使用useState()或useReducer()從組件內(nèi)部進(jìn)行管理。

跨組件狀態(tài)??它是一種影響多個組件的狀態(tài),例如觸發(fā)模態(tài)覆蓋的按鈕,可以從某處的按鈕打開并由模態(tài)內(nèi)的另一個按鈕關(guān)閉毯辅。useState()或useReducer()可以通過使用props來管理此類行為。

App-wide state ??它是一種影響應(yīng)用程序所有組件的狀態(tài)煞额,例如用戶身份驗證思恐,登錄后導(dǎo)航欄顯示更多選項,其他組件更新膊毁。

?? Redux 與 React 上下文

React Context是一個集成功能胀莹,它還允許我們通過創(chuàng)建管理狀態(tài)的上下文提供程序組件來避免 prop 鏈。但是媚媒,它有一些潛在的缺點嗜逻,可能不會影響應(yīng)用程序的開發(fā)。需要注意的是缭召,應(yīng)用程序不限于一種狀態(tài)管理栈顷,兩者都可以在同一個應(yīng)用程序中使用。通常嵌巷,只有一個用于應(yīng)用程序的寬狀態(tài)萄凤,React Context仍然可以用于選定的多組件狀態(tài),這在應(yīng)用程序的某些部分很重要搪哪。

React 上下文缺點

  • 它在復(fù)雜的設(shè)置中效果不佳 ?? 這取決于應(yīng)用程序的大小靡努,但對于中小型應(yīng)用程序可能不是問題。但是,在具有影響多個組件和許多上下文提供者的各種狀態(tài)的大型應(yīng)用程序中惑朦,開發(fā)人員最終可能會得到深度嵌套的 JSX 代碼兽泄。

  • 性能?? 據(jù) React 團(tuán)隊的一位成員介紹,useContext的使用對于低頻率更新(更改主題漾月、身份驗證等)非常有用病梢,但在數(shù)據(jù)變化很大時效果不佳,因此不是替代類似通量的狀態(tài)傳播梁肿。另一方面蜓陌,Redux是一個類似 Flux 的狀態(tài)管理庫,而useContext并不是它的好替代品吩蔑。

(如果您想了解更多關(guān)于Flux 架構(gòu)模式的信息钮热,這里是一個鏈接)

?? 理論上的 Redux

Redux的主要目標(biāo)是創(chuàng)建一個中央數(shù)據(jù)存儲,負(fù)責(zé)管理整個應(yīng)用程序的狀態(tài)烛芬。確實隧期,在這個 store 中,可以處理所有的跨組件狀態(tài)蛀骇,如認(rèn)證厌秒、主題化读拆、用戶輸入等。 store 中包含的數(shù)據(jù)可以在組件中使用,如果某些數(shù)據(jù)發(fā)生變化主儡,組件可以做出相應(yīng)的反應(yīng)并更新 UI逗威。為此,組件訂閱中央存儲辟灰,當(dāng)數(shù)據(jù)發(fā)生變化時个榕,存儲會通知組件。

組件如何更改存儲中的數(shù)據(jù)

組件從不直接操作存儲數(shù)據(jù)芥喇∥鞑桑基本上,組件通過訂閱可以直接訪問存儲數(shù)據(jù)继控,但沒有直接數(shù)據(jù)流向另一個方向械馆。相反,需要設(shè)置的reducer函數(shù)負(fù)責(zé)改變存儲數(shù)據(jù)(術(shù)語reducer已經(jīng)表示一種接受一些輸入武通、轉(zhuǎn)換輸入并返回新結(jié)果的函數(shù))霹崎。

Actions用于觸發(fā)reducer函數(shù),而不是直接訪問 store冶忱,組件可以調(diào)度這些actions尾菇。然后該操作被轉(zhuǎn)發(fā)到reducer,它讀取并執(zhí)行所需操作的描述。reducer返回一個新狀態(tài)派诬,它替換中央數(shù)據(jù)存儲中的現(xiàn)有狀態(tài)劳淆。最后,當(dāng)狀態(tài)更新時默赂,所有訂閱組件都會收到通知憔儿,以便它們可以更新 UI。

?? 安裝 Redux

以下說明可以在Redux 官方網(wǎng)站上找到放可。

"推薦使用 React 和 Redux 啟動新應(yīng)用的方法是使用官方 Redux+JS 模板或 Redux+TS 模板來創(chuàng)建 React App谒臼,它利用了 Redux Toolkit 和 React Redux 與 React 組件的集成。 "

# Redux + Plain JS template
npx create-react-app my-app --template redux

# Redux + TypeScript template
npx create-react-app my-app --template redux-typescript

" Redux 核心庫作為 NPM 上的一個包提供耀里,可與模塊捆綁器或 Node 應(yīng)用程序一起使用: "

# NPM
npm install redux

# Yarn
yarn add redux

?? 實戰(zhàn)前的 Redux 基礎(chǔ)

現(xiàn)在我們玩Redux來了解它的機制蜈缤。

在應(yīng)用程序中創(chuàng)建一個新的 JS 文件(我稱之為 redux-demo.js)后,可以從Redux中導(dǎo)入createStore函數(shù)并使用它來創(chuàng)建我們的商店冯挎。

import {createStore} from 'redux';

const store = createStore();

createStore函數(shù)需要一個參數(shù)底哥,該參數(shù)是reducer 用于生成新的狀態(tài)快照房官。reducer還使用默認(rèn)操作執(zhí)行趾徽,該操作應(yīng)返回初始狀態(tài)

// Giving state a default value of {counter: 0}
const counterReducer = (state = {counter: 0}, action) => {
    return {
        counter: state.counter + 1
    }
};

const store = createStore(counterReducer);

創(chuàng)建reducer函數(shù)時翰守,必須包含兩個參數(shù)孵奶,舊狀態(tài)和分派動作。此外蜡峰,它必須始終返回一個新的狀態(tài)對象了袁。因此,reducer函數(shù)是一個“純函數(shù)”湿颅,這意味著相同的輸入值應(yīng)該始終產(chǎn)生完全相同的輸出载绿,并且內(nèi)部不應(yīng)該有 HTTP 或本地存儲請求等副作用。

const counterSubscriber = () => {
    const latestState = store.getState();
    console.log(latestState)
};

store.subscribe(counterSubscriber);

Redux通過訂閱store并將訂閱者函數(shù)本身作為參數(shù)傳遞來了解訂閱者函數(shù)油航。

.getState()返回更新后的最新狀態(tài)快照崭庸,因此它在狀態(tài)更改后運行。

store.dispatch({type: "increment"});

分派是一種分派動作的方法谊囚。action是一個帶有type屬性的JS 對象怕享,它充當(dāng)標(biāo)識符,通常是唯一的字符串秒啦。

嘗試使用命令node [file name].js(在我的例子中 為 node redux-demo.js )在終端上運行以下代碼:

import {createStore} from 'redux'

const counterReducer = (state = {counter: 0}, action) => {
    return {
        counter: state.counter + 1
    }
};

const store = createStore(counterReducer);

const counterSubscriber = () => {
    const latestState = store.getState();
    console.log(latestState)
};

store.subscribe(counterSubscriber);

store.dispatch({type: "increment"});

(如果您收到“ SyntaxError: Cannot use import statement outside a module ”熬粗,只需在 package.json 中添加 “type”:“module” )

在終端上,您現(xiàn)在應(yīng)該能夠看到:

{ counter: 2 }

計數(shù)器在初始化時增加余境,并在分派操作時再次增加驻呐。

盡管一切正常灌诅,但這并不是Redux所期望的行為,因為主要目標(biāo)是在 reducer 中為不同的操作做不同的事情含末。因此猜拾,是時候使用 reducer 函數(shù)的第二個參數(shù)action了。

import {createStore} from 'redux'

const counterReducer = (state = {counter: 0}, action) => {
    if (action.type === "increment") {
        return {counter: state.counter + 1}
    }

    if (action.type === "decrement") {
        return {counter: state.counter - 1}
    }

    return state;
};

const store = createStore(counterReducer);

const counterSubscriber = () => {
    const latestState = store.getState();
    console.log(latestState)
};

store.subscribe(counterSubscriber);

store.dispatch({type: "increment"});
store.dispatch({type: "decrement"});

如果我們再次運行該文件佣盒,結(jié)果應(yīng)該是:

{ counter: 1 }
{ counter: 0 }

初始化時挎袜,reducer返回原始狀態(tài),之后狀態(tài)由調(diào)度函數(shù)遞增和遞減肥惭,計數(shù)器為 0盯仪。

?? React + Redux 實戰(zhàn)

在現(xiàn)有應(yīng)用程序中實現(xiàn) Redux。

由于Redux不是特定于 react 的蜜葱,但可以在任何 JavaScript 項目中使用全景,我們還將使用第二個名為react-redux的包。

這個包包括一個組件以使商店對整個應(yīng)用程序可用牵囤,以及一對自定義鉤子useSelectoruseDispatch允許組件與商店交互爸黄。

// In the terminal
npm i redux react-redux

更多信息可以在官方網(wǎng)站上找到。

按照慣例揭鳞,通常會創(chuàng)建一個名為store的文件夾并將所有與Redux相關(guān)的文件放在其中炕贵。然后我創(chuàng)建一個index.js文件,但是你可以隨意調(diào)用它野崇。

讓我們像之前一樣創(chuàng)建一個簡單的計數(shù)器称开,并導(dǎo)出store變量以提供應(yīng)用程序的組件:

// src/store/index.js

import {createStore} from "redux"

function counterReducer(state = {counter: 0}, action) {
    switch (action.type) {
        case 'increment':
            return {counter: state.counter + 1}
        case 'decrement':
            return {counter: state.counter - 1}
        default:
            return state
    }
}

const store = createStore(counterReducer)

export default store

src/index.js文件中,它位于我們的應(yīng)用程序樹的頂部舞骆,也是我們渲染整個應(yīng)用程序的地方钥弯,我們導(dǎo)入:

import {Provider} from "react-redux";

隨著我們可以包裝 , 并通過我們的store來存儲Provider 的 store prop

// src/index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import {Provider} from "react-redux";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Provider store={store}><App/></Provider>);

在 React 組件中使用 Redux 數(shù)據(jù)

要從組件中訪問store數(shù)據(jù)督禽,我們可以從 react redux 庫中導(dǎo)入useSelectoruseStore鉤子。第一個非常方便总处,因為它允許我們從商店中提取某些變量狈惫。但是,react-redux 文檔建議您通常更喜歡useSelector

useSelector:當(dāng)一個動作被調(diào)度時鹦马, useSelector() 將對先前的選擇器結(jié)果值和當(dāng)前結(jié)果值進(jìn)行參考比較胧谈。如果它們不同,組件將被強制重新渲染荸频。如果它們相同菱肖,則組件不會重新渲染。

useStore:這個鉤子可能不應(yīng)該經(jīng)常使用旭从。首選 useSelector() 作為您的主要選擇稳强。但是场仲,這對于需要訪問存儲的不太常見的場景(例如更換減速器)可能很有用。

useSelector鉤子接受一個函數(shù)退疫,該函數(shù)確定我們要從存儲中提取哪條數(shù)據(jù)渠缕,因此計數(shù)器變量,因為它是唯一存在的褒繁。通過使用這個鉤子亦鳞,react-redux 為組件創(chuàng)建了對Redux Store的訂閱,以便在每次數(shù)據(jù)更改時自動更新棒坏。

import classes from './Counter.module.css';
import {useSelector} from "react-redux";

const Counter = () => {
    const counter = useSelector(state => state.counter)

    return (
        <main className={classes.counter}>
            <h1>Redux Counter</h1>
            <div className={classes.value}>{counter}</div>
        </main>
    );
};

export default Counter;

從組件調(diào)度操作

為了從組件內(nèi)調(diào)度動作燕差,react-redux 提供了另一個名為useDispatch的鉤子。調(diào)用鉤子時坝冕,不需要任何參數(shù)谁不,因為它只返回一個可以在執(zhí)行時發(fā)送動作的函數(shù)。在函數(shù)的執(zhí)行中徽诲,現(xiàn)在可以提供一個對象刹帕,該對象包含與更新計數(shù)器的操作相關(guān)聯(lián)的類型。

import classes from './Counter.module.css';
import {useDispatch, useSelector} from "react-redux";

const Counter = () => {
    const dispatch = useDispatch();
    const counter = useSelector(state => state.counter);

    const incrementHandler = () => {
        dispatch({type: "increment"});
    };

    const decrementHandler = () => {
        dispatch({type: "decrement"});
    };

    return (
        <main className={classes.counter}>
            <h1>Redux Counter</h1>
            <div className={classes.value}>{counter}</div>
            <div>
                <button onClick={incrementHandler}>Increment</button>
                <button onClick={decrementHandler}>Decrement</button>
            </div>
        </main>
    );
};

export default Counter;

將有效負(fù)載附加到操作

到目前為止谎替,我們已經(jīng)了解了如何發(fā)送簡單的操作偷溺,但有時操作也可以有一個稱為有效負(fù)載的附加值。在 dispatch 函數(shù)中钱贯,除了類型挫掏,我們可以隨意添加和命名其他值。讓我們?yōu)?reducer 函數(shù)創(chuàng)建一個新的案例場景秩命,它需要一個額外的值尉共,稱為 amount。

// src/store/index.js
function counterReducer(state = {counter: 0}, action) {
    switch (action.type) {
       ...
        case 'increase':
            return {counter: state.counter + action.amount}
        ...
    }
}

在組件中弃锐,我們可以創(chuàng)建一個新的處理程序來調(diào)度這個帶有額外“數(shù)量”值的新動作袄友,并將它傳遞給一個新按鈕。

// Component

import classes from './Counter.module.css';
import {useDispatch, useSelector} from "react-redux";

const Counter = () => {
    const dispatch = useDispatch();
    const counter = useSelector(state => state.counter);

    [...]

    const decrementHandler = () => {
        dispatch({type: "decrement"});
    };

    return (
        <main className={classes.counter}>
            <h1>Redux Counter</h1>
            <div className={classes.value}>{counter}</div>
            <div>
                <button onClick={incrementHandler}>Increment</button>
                <button onClick={decrementHandler}>Decrement</button>
                <button onClick={increaseHandler}>Increase by 3</button>
            </div>
        </main>
    );
};

export default Counter;

與多個全局狀態(tài)一起工作

計數(shù)器狀態(tài)可能不是我們想要處理的唯一全局狀態(tài)霹菊。因此剧蚣,讓我們添加一個新的切換狀態(tài)來使用幾個全局狀態(tài)來練習(xí)我們的計數(shù)器。添加新狀態(tài)時旋廷,我們還必須在其他情況下處理它鸠按,否則我們可能會覆蓋其他狀態(tài)變量并破壞應(yīng)用程序。

function counterReducer(state = initialState, action) {
    switch (action.type) {
        case 'increment':
            return {...state, counter: state.counter + 1}
        case 'decrement':
            return {...state, counter: state.counter - 1}
        case 'increase':
            return {...state, counter: state.counter + action.amount}
        case 'toggle':
            return {...state, showCounter: !state.showCounter}
        default:
            return state
    }
}

在組件內(nèi)部饶碘,選擇新的ShowCounter 狀態(tài)并將其添加到 JSX 邏輯中:

import classes from './Counter.module.css';
import {useDispatch, useSelector} from "react-redux";

const Counter = () => {
    const dispatch = useDispatch();
    const {counter, showCounter} = useSelector(state => state);

    const toggleCounterHandler = () => {
        dispatch({type: "toggle"})
    };

    const incrementHandler = () => {
        dispatch({type: "increment"});
    };

    const increaseHandler = () => {
        dispatch({type: "increase", amount: 3});
    };

    const decrementHandler = () => {
        dispatch({type: "decrement"});
    };

    return (
        <main className={classes.counter}>
            <h1>Redux Counter</h1>
            {showCounter && <div className={classes.value}>{counter}</div>}
            <div>
                <button onClick={incrementHandler}>Increment</button>
                <button onClick={decrementHandler}>Decrement</button>
                <button onClick={increaseHandler}>Increase by 3</button>
            </div>
            <button onClick={toggleCounterHandler}>Toggle Counter</button>
        </main>
    );
};

export default Counter;

?? Redux 工具包

Redux Toolkit 是一個幫助開發(fā)人員使用 Redux 并防止錯誤的庫目尖。該包旨在成為編寫 Redux 邏輯的標(biāo)準(zhǔn)方式,因此值得擁有自己的部分扎运。您可以在Redux Tollkit 網(wǎng)站上找到更多信息瑟曲。

安裝:

# NPM
npm install @reduxjs/toolkit

# Yarn
yarn add @reduxjs/toolkit

Redux 庫可以從 package.json 中刪除饮戳,因為它已經(jīng)包含在 reduxjs/toolkit 中。

創(chuàng)建切片

此功能允許開發(fā)人員創(chuàng)建不同的全局狀態(tài)切片测蹲。如果我們有不直接相關(guān)的不同狀態(tài)莹捡,例如身份驗證和計數(shù)器狀態(tài),這將很有用扣甲。此外篮赢,我們可以在不同的文件中創(chuàng)建切片,以獲得更易于管理的代碼琉挖。 createSlice接受一個對象作為參數(shù)启泣,我們可以在其中添加相關(guān)的countershowcounter邏輯。

每個切片都需要一個name示辈、一個initialState和一個reducers對象寥茫。后者包含方法,每個方法都有一個名稱并接收最新狀態(tài)的副本矾麻。這樣的結(jié)構(gòu)可以讓開發(fā)者停止編寫 if/case 檢查纱耻,減少代碼的長度,使其更具可讀性险耀。

與之前的 reducer 方法不同弄喘,我們現(xiàn)在可以改變state,或者至少看起來如此甩牺!事實上蘑志,Redux ToolkitcreateSlice函數(shù)不會意外操作現(xiàn)有state,因為Redux Toolkit在內(nèi)部使用另一個名為Immer的包贬派,它克隆現(xiàn)有state急但,創(chuàng)建一個新的state對象,保存所有未編輯的狀態(tài)并覆蓋我們在 an不可變的方式(查看更多)搞乏。此功能使開發(fā)人員的工作更加輕松和安全波桩,因為我們不再需要擔(dān)心重寫狀態(tài)一遍又一遍地為每種方法。當(dāng)需要有效負(fù)載時查描,我們也可以接受action參數(shù)并在方法中使用它。

這是我們新創(chuàng)建的切片的外觀:

import {createStore} from "redux";
import {createSlice} from "@reduxjs/toolkit";

const initialState = {counter: 0, showCounter: true}

const counterSlice = createSlice({
    name: "counter",
    initialState,
    reducers: {
        increment(state) {
            state.counter++
        },
        decrement(state) {
            state.counter--
        },
        increase(state, action) {
            state.counter += action.amount
        },
        toggleCounter(state) {
            state.showCounter = !state.showCounter
        }
    }
});

連接 Redux 工具包狀態(tài)

在我們的例子中,我們可以簡單地將counterSlice.reducer作為 store 的參數(shù)傳遞缘缚,它會起作用:

const store = createStore(counterSlice.reducer)

但是,如果我們有多個切片桥滨,我們可以使用標(biāo)準(zhǔn)的 Redux 函數(shù)combineReducers甚至更好的是 Redux Toolkit 提供 的configureStore函數(shù)弛车。configureStorecreateStore的替代品蒲每,但它使合并 reducer 更容易。它接受一個配置對象作為參數(shù)邀杏,它需要一個 reducer 屬性。reducer 屬性可以接受單個 reducer望蜡,或者,如果應(yīng)用程序有多個切片脖律,則可以接受包含要合并的所有 reducer 的對象。

const store = configureStore({
    reducer: counterSlice.reducer
})

#OR

const store = configureStore({
    reducer: {counter: counterSlice.reducer}
})

調(diào)度

createSlice自動為所有reducer創(chuàng)建標(biāo)識符芦疏,要訪問它們,我們可以簡單地從sliceName.actions中選擇它們酸茴。我們現(xiàn)在可以使用Redux Toolkit創(chuàng)建的方法,當(dāng)調(diào)用該方法時弊决,會創(chuàng)建已經(jīng)具有type屬性的action 對象魁淳,每個action都有一個唯一標(biāo)識符飘诗。因此,作為開發(fā)人員界逛,我們不再需要擔(dān)心創(chuàng)建操作對象唯一標(biāo)識符或避免拼寫錯誤±ジ澹現(xiàn)在我們可以導(dǎo)出文件底部的所有動作:

import {configureStore, createSlice} from "@reduxjs/toolkit";

[...]

const store = configureStore({
    reducer: {counter: counterSlice.reducer}
})

export const counterActions = counterSlice.actions
export default store

回到 Counter 組件,我們可以導(dǎo)入這些操作并相應(yīng)地重構(gòu)我們的代碼:

import {useDispatch, useSelector} from "react-redux";
import {counterActions} from "../store";

const Counter = () => {
    const dispatch = useDispatch();
/* Change useSelector(state => state)
 to useSelector(state => state.counter) */
    const {counter, showCounter} = useSelector(state => state.counter);

    const toggleCounterHandler = () => {
        dispatch(counterActions.toggleCounter())
    };

    const incrementHandler = () => {
        dispatch(counterActions.increment());
    };

    const increaseHandler = () => {
        dispatch(counterActions.increase(3));
    };

    const decrementHandler = () => {
        dispatch(counterActions.decrement());
    };

    [...]

對增加減速器的另一個小改動息拜,現(xiàn)在默認(rèn)情況下溉潭,數(shù)量變?yōu)?/em>有效負(fù)載

increase(state, action) {
            state.counter += action.payload
        },

多個切片的示例

向 React 應(yīng)用程序添加更多切片時,存在創(chuàng)建過長文件的風(fēng)險少欺≡辏可能值得將其拆分為更小的部分并為創(chuàng)建的每個切片創(chuàng)建一個文件。

// store/index.js

import {configureStore} from "@reduxjs/toolkit";
import counterSliceReducer from './counter'
import authSliceReducer from './auth'

const store = configureStore({
    reducer: {counter: counterSliceReducer, auth: authSliceReducer}
});

export default store;

// store/counter.js

import {createSlice} from "@reduxjs/toolkit";

const initialCounterState = {counter: 0, showCounter: true};

const counterSlice = createSlice({
    name: "counter",
    initialState: initialCounterState,
    reducers: {
        increment(state) {
            state.counter++
        },
        decrement(state) {
            state.counter--
        },
        increase(state, action) {
            state.counter += action.payload
        },
        toggleCounter(state) {
            state.showCounter = !state.showCounter
        }
    }
});
export const counterActions = counterSlice.actions;
export default counterSlice.reducer

import {createSlice} from "@reduxjs/toolkit";

const authInitialState = {isAuthenticated: false};

const authSlice = createSlice({
    name: "auth",
    initialState: authInitialState,
    reducers: {
        login(state) {
            state.isAuthenticated = true
        },
        logout(state) {
            state.isAuthenticated = false
        }
    }
});

export const authActions = authSlice.actions
export default authSlice.reducer

重構(gòu)代碼后不要忘記修復(fù)小的導(dǎo)入錯誤赞别!

文章來源:https://pietropiraino.hashnode.dev/react-redux-redux-toolkit

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末畏陕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仿滔,更是在濱河造成了極大的恐慌惠毁,老刑警劉巖犹芹,帶你破解...
    沈念sama閱讀 211,639評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異鞠绰,居然都是意外死亡腰埂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評論 3 385
  • 文/潘曉璐 我一進(jìn)店門蜈膨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來屿笼,“玉大人,你說我怎么就攤上這事丈挟〉蟛罚” “怎么了?”我有些...
    開封第一講書人閱讀 157,221評論 0 348
  • 文/不壞的土叔 我叫張陵曙咽,是天一觀的道長蛔趴。 經(jīng)常有香客問我,道長例朱,這世上最難降的妖魔是什么孝情? 我笑而不...
    開封第一講書人閱讀 56,474評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮洒嗤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘渔隶。我一直安慰自己间唉,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,570評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著被冒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝗锥。 梳的紋絲不亂的頭發(fā)上玛追,一...
    開封第一講書人閱讀 49,816評論 1 290
  • 那天痊剖,我揣著相機與錄音陆馁,去河邊找鬼叮贩。 笑死益老,一個胖子當(dāng)著我的面吹牛寸莫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桃纯,決...
    沈念sama閱讀 38,957評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼态坦,長吁一口氣:“原來是場噩夢啊……” “哼伞梯!你這毒婦竟也來了谜诫?” 一聲冷哼從身側(cè)響起猜绣,我...
    開封第一講書人閱讀 37,718評論 0 266
  • 序言:老撾萬榮一對情侶失蹤掰邢,失蹤者是張志新(化名)和其女友劉穎辣之,沒想到半個月后怀估,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,176評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡歧蕉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,511評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了催跪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片夷野。...
    茶點故事閱讀 38,646評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡骑丸,死狀恐怖鳖孤,靈堂內(nèi)的尸體忽然破棺而出苏揣,到底是詐尸還是另有隱情平匈,我是刑警寧澤,帶...
    沈念sama閱讀 34,322評論 4 330
  • 正文 年R本政府宣布忍燥,位于F島的核電站梅垄,受9級特大地震影響队丝,放射性物質(zhì)發(fā)生泄漏机久。R本人自食惡果不足惜膘盖,卻給世界環(huán)境...
    茶點故事閱讀 39,934評論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望结缚。 院中可真熱鬧掺冠,春花似錦、人聲如沸斥黑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽茴恰。三九已至,卻和暖如春伐庭,著一層夾襖步出監(jiān)牢的瞬間圾另,已是汗流浹背雕沉。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評論 1 266
  • 我被黑心中介騙來泰國打工扰路, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留幼衰,地道東北人缀雳。 一個月前我還...
    沈念sama閱讀 46,358評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像绝葡,于是被迫代替她去往敵國和親藏畅。 傳聞我的和親對象是個殘疾皇子愉阎,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,514評論 2 348

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