react hooks 萬字總結(jié),帶你夯實基礎(chǔ)

react hooks

react hooks 萬字總結(jié),帶你夯實基礎(chǔ)

前言

自己在掘金上看了也看了很多關(guān)于hooks的文章,感覺都講得不是很詳細。而且也有很多的水文。最近自己打算重學react,系統(tǒng)性的再把hooks給學習一遍。

Hooks is what?

  • react-hooks是react16.8以后,react新增的鉤子API,它可以讓你在不編寫 class 的情況下使用 state 以及其他的 React 特性.
  • Hook是一些可以讓你在函數(shù)組件里“鉤入” React state 及生命周期等特性的函數(shù)。

why use Hooks?

類組件的缺點:(來自官網(wǎng)動機

  • 在組件之間復用狀態(tài)邏輯很難

  • 復雜組件變得難以理解

  • 難以理解的 class

你必須去理解 JavaScript 中 this 的工作方式,這與其他語言存在巨大差異。還不能忘記綁定事件處理器。沒有穩(wěn)定的語法提案,代碼非常冗余。

hooks的出現(xiàn),解決了上面的問題。另外,還有一些其他的優(yōu)點

  • 增加代碼的可復用性,邏輯性,彌補無狀態(tài)組件沒有生命周期,沒有數(shù)據(jù)管理狀態(tài)state的缺陷
  • react-hooks思想更趨近于函數(shù)式編程。用函數(shù)聲明方式代替class聲明方式,雖說class也是es6構(gòu)造函數(shù)語法糖,但是react-hooks寫起來函數(shù)即是組件,無疑也提高代碼的開發(fā)效率(無需像class聲明組件那樣寫聲明周期,寫生命周期render函數(shù)等)

Hooks沒有破壞性改動

  • 完全可選的。 你無需重寫任何已有代碼就可以在一些組件中嘗試 Hook。但是如果你不想,你不必現(xiàn)在就去學習或使用 Hook。
  • 100% 向后兼容的。 Hook 不包含任何破壞性改動。
  • 現(xiàn)在可用。 Hook 已發(fā)布于 v16.8.0。

使用Hooks的規(guī)則

1. 只在最頂層使用 Hook,不要在循環(huán),條件或嵌套函數(shù)中調(diào)用 Hook

確保總是在你的 React 函數(shù)的最頂層調(diào)用他們。遵守這條規(guī)則,你就能確保 Hook 在每一次渲染中都按照同樣的順序被調(diào)用。這讓 React 能夠在多次的 useStateuseEffect 調(diào)用之間保持 hook 狀態(tài)的正確。

2. 只在 React 函數(shù)中調(diào)用 Hook

不要在普通的 JavaScript 函數(shù)中調(diào)用 Hook,你可以:

  • ? 在 React 的函數(shù)組件中調(diào)用 Hook
  • ? 在自定義 Hook 中調(diào)用其他 Hook

至于為什么會有這些規(guī)則,如果你感興趣,請參考Hook 規(guī)則

useState

const [state, setState] = useState(initialState)

  • useState 有一個參數(shù)(initialState 可以是一個函數(shù),返回一個值,但一般都不會這么用),該參數(shù)可以為任意數(shù)據(jù)類型,一般用作默認值.
  • useState 返回值為一個數(shù)組,數(shù)組的第一個參數(shù)為我們需要使用的 state,第二個參數(shù)為一個改變state的函數(shù)(功能和this.setState一樣)

來看一個計時器的案例

import React,{useState} from "react";
function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
export default Example;
復制代碼
  • 第一行: 引入 React 中的 useState Hook。它讓我們在函數(shù)組件中存儲內(nèi)部 state。
  • 第三行:Example 組件內(nèi)部,我們通過調(diào)用 useState Hook 聲明了一個新的 state 變量。它返回一對值給到我們命名的變量上。我們把變量命名為 count,因為它存儲的是點擊次數(shù)。我們通過傳 0 作為 useState 唯一的參數(shù)來將其初始化為 0。第二個返回的值本身就是一個函數(shù)。它讓我們可以更新 count 的值,所以我們叫它 setCount
  • 第七行: 當用戶點擊按鈕后,我們傳遞一個新的值給 setCount。React 會重新渲染 Example 組件,并把最新的 count 傳給它。

使用多個state 變量

 // 聲明多個 state 變量
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: '學習 Hook' }]);
復制代碼

不必使用多個 state 變量。State 變量可以很好地存儲對象和數(shù)組,因此,你仍然可以將相關(guān)數(shù)據(jù)分為一組。

更新State

import React,{useState} from "react";
function Example() {
  const [count, setCount] = useState(0);
  const [person, setPerson] = useState({name:'jimmy',age:22});
  return (
    <div>
      <p>name {person.name} </p>
      // 如果新的 state 需要通過使用先前的 state 計算得出,那么可以將回調(diào)函數(shù)當做參數(shù)傳遞給 setState。
      // 該回調(diào)函數(shù)將接收先前的 state,并返回一個更新后的值。
      <button onClick={() => setCount(count=>count+1)}>Click me</button>
      <button onClick={() => setPerson({name:'chimmy'})}>Click me</button>
    </div>
  );
}
export default Example;
復制代碼

setPerson更新person時,不像 class 中的 this.setState,更新 state 變量總是替換它而不是合并它。上例中的person為{name:'chimmy'} 而不是{name:'chimmy',age:22}

useEffect

Effect Hook 可以讓你在函數(shù)組件中執(zhí)行副作用(數(shù)據(jù)獲取,設(shè)置訂閱以及手動更改 React 組件中的 DOM 都屬于副作用)操作

useEffect(fn, array)

useEffect在初次完成渲染之后都會執(zhí)行一次, 配合第二個參數(shù)可以模擬類的一些生命周期。

如果你熟悉 React class 的生命周期函數(shù),你可以把 useEffect Hook 看做 componentDidMount``componentDidUpdatecomponentWillUnmount 這三個函數(shù)的組合。

useEffect 實現(xiàn)componentDidMount

如果第二個參數(shù)為空數(shù)組,useEffect相當于類組件里面componentDidMount。

import React, { useState, useEffect } from "react";
function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("我只會在組件初次掛載完成后執(zhí)行");
  }, []);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
export default Example;
復制代碼

頁面渲染完成后,會執(zhí)行一次useEffect。打印“我只會在組件初次掛載完成后執(zhí)行”,當點擊按鈕改變了state,頁面重新渲染后,useEffect不會執(zhí)行。

useEffect 實現(xiàn)componentDidUpdate

如果不傳第二個參數(shù),useEffect 會在初次渲染和每次更新時,都會執(zhí)行。

import React, { useState, useEffect } from "react";
function Example() {
  const [count, setCount] = useState(0);
  useEffect(() => {
    console.log("我會在初次組件掛載完成后以及重新渲染時執(zhí)行");
  });
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
export default Example;
復制代碼

初次渲染時,會執(zhí)行一次useEffect,打印出“我會在初次組件掛載完成后以及重新渲染時執(zhí)行”。 當點擊按鈕時,改變了state,頁面重新渲染,useEffect都會執(zhí)行,打印出“我會在初次組件掛載完成后以及重新渲染時執(zhí)行”。

useEffect 實現(xiàn)componentWillUnmount

effect 返回一個函數(shù),React 將會在執(zhí)行清除操作時調(diào)用它。

useEffect(() => {
    console.log("訂閱一些事件");
    return () => {
      console.log("執(zhí)行清除操作")
    }
  },[]);
復制代碼

注意:這里不只是組件銷毀時才會打印“執(zhí)行清除操作”,每次重新渲染時也都會執(zhí)行。至于原因,我覺得官網(wǎng)解釋的很清楚,請參考 解釋: 為什么每次更新的時候都要運行 Effect

控制useEffect的執(zhí)行

import React, { useState, useEffect } from "react";
function Example() {
  const [count, setCount] = useState(0);
  const [number, setNumber] = useState(1);
  useEffect(() => {
    console.log("我只會在cout變化時執(zhí)行");
  }, [count]);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click cout</button>
      <button onClick={() => setNumber(number + 1)}>Click number</button>
    </div>
  );
}
export default Example;
復制代碼

上面的例子,在點擊 click cout按鈕時,才會打印“我只會在cout變化時執(zhí)行”。 因為useEffect 的第二個參數(shù)的數(shù)組里面的依賴是cout,所以,只有cout發(fā)生改變時,useEffect 才會執(zhí)行。如果數(shù)組中有多個元素,即使只有一個元素發(fā)生變化,React 也會執(zhí)行 effect。

使用多個 Effect 實現(xiàn)關(guān)注點分離

使用 Hook 其中一個目的就是要解決 class 中生命周期函數(shù)經(jīng)常包含不相關(guān)的邏輯,但又把相關(guān)邏輯分離到了幾個不同方法中的問題。

import React, { useState, useEffect } from "react";
function Example() {
  useEffect(() => {
    // 邏輯一
  });
  useEffect(() => {
    // 邏輯二
  });
   useEffect(() => {
    // 邏輯三
  });
  return (
    <div>
      useEffect的使用
    </div>
  );
}
export default Example;
復制代碼

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

useEffect中使用異步函數(shù)

useEffect是不能直接用 async await 語法糖的

/* 錯誤用法 ,effect不支持直接 async await*/
 useEffect(async ()=>{
        /* 請求數(shù)據(jù) */
      const res = await getData()
 },[])
復制代碼

useEffect 的回調(diào)參數(shù)返回的是一個清除副作用的 clean-up 函數(shù)。因此無法返回 Promise,更無法使用 async/await

那我們應(yīng)該如何讓useEffect支持async/await呢?

方法一(推薦)

const App = () => {
  useEffect(() => {
    (async function getDatas() {
      await getData();
    })();
  }, []);
  return <div></div>;
};
復制代碼

方法二

  useEffect(() => {
    const getDatas = async () => {
      const data = await getData();
      setData(data);
    };
    getDatas();
  }, []);
復制代碼

useEffect 做了什么

通過使用這個 Hook,你可以告訴 React 組件需要在渲染后執(zhí)行某些操作。React 會保存你傳遞的函數(shù)(我們將它稱之為 “effect”),并且在執(zhí)行 DOM 更新之后調(diào)用它。

為什么在組件內(nèi)部調(diào)用 useEffect

useEffect 放在組件內(nèi)部讓我們可以在 effect 中直接訪問 count state 變量(或其他 props)。我們不需要特殊的 API 來讀取它 —— 它已經(jīng)保存在函數(shù)作用域中。Hook 使用了 JavaScript 的閉包機制,而不用在 JavaScript 已經(jīng)提供了解決方案的情況下,還引入特定的 React API。

useContext

概念

const value = useContext(MyContext);

接收一個 context 對象(React.createContext 的返回值)并返回該 context 的當前值。當組件上層最近的 <MyContext.Provider> 更新時,該 Hook 會觸發(fā)重渲染,并使用最新傳遞給 MyContext provider 的 context value 值。即使祖先使用 React.memoshouldComponentUpdate,也會在組件本身使用 useContext 時重新渲染。

別忘記 useContext 的參數(shù)必須是 context 對象本身

  • 正確: useContext(MyContext)
  • 錯誤: useContext(MyContext.Consumer)
  • 錯誤: useContext(MyContext.Provider)

示例

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
// 創(chuàng)建兩個context
export const UserContext = React.createContext();
export const TokenContext = React.createContext();
ReactDOM.render(
  <UserContext.Provider value={{ id: 1, name: "chimmy", age: "20" }}>
    <TokenContext.Provider value="我是token">
      <App />
    </TokenContext.Provider>
  </UserContext.Provider>,
  document.getElementById("root")
);
復制代碼

app.js

import React, { useContext } from "react";
import { UserContext, TokenContext } from "./index";

function Example() {
  let user = useContext(UserContext);
  let token = useContext(TokenContext);
  console.log("UserContext", user);
  console.log("TokenContext", token);
  return (
    <div>
      name:{user?.name},age:{user?.age}
    </div>
  );
}
export default Example;
復制代碼

打印的值如下

image.png

提示

如果你在接觸 Hook 前已經(jīng)對 context API 比較熟悉,那應(yīng)該可以理解,useContext(MyContext) 相當于 class 組件中的 static contextType = MyContext 或者 <MyContext.Consumer>

useContext(MyContext) 只是讓你能夠讀取 context 的值以及訂閱 context 的變化。你仍然需要在上層組件樹中使用 <MyContext.Provider> 來為下層組件提供 context。

useReducer

概念

const [state, dispatch] = useReducer(reducer, initialArg, init);

useState 的替代方案。它接收一個形如 (state, action) => newState 的 reducer,并返回當前的 state 以及與其配套的 dispatch 方法。(如果你熟悉 Redux 的話,就已經(jīng)知道它如何工作了。)

在某些場景下,useReducer 會比 useState 更適用,例如 state 邏輯較復雜且包含多個子值,或者下一個 state 依賴于之前的 state 等。并且,使用 useReducer 還能給那些會觸發(fā)深更新的組件做性能優(yōu)化,因為你可以向子組件傳遞 dispatch 而不是回調(diào)函數(shù)

注意點

React 會確保 dispatch 函數(shù)的標識是穩(wěn)定的,并且不會在組件重新渲染時改變。這就是為什么可以安全地從 useEffectuseCallback 的依賴列表中省略 dispatch

示例

import React, { useReducer } from "react";
export default function Home() {
  function reducer(state, action) {
    switch (action.type) {
      case "increment":
        return { ...state, counter: state.counter + 1 };
      case "decrement":
        return { ...state, counter: state.counter - 1 };
      default:
        return state;
    }
  }
  const [state, dispatch] = useReducer(reducer, { counter: 0 });
  return (
    <div>
      <h2>Home當前計數(shù): {state.counter}</h2>
      <button onClick={(e) => dispatch({ type: "increment" })}>+1</button>
      <button onClick={(e) => dispatch({ type: "decrement" })}>-1</button>
    </div>
  );
}
復制代碼

useCallback

概念

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
復制代碼

返回一個 [memoized]回調(diào)函數(shù)。

把內(nèi)聯(lián)回調(diào)函數(shù)及依賴項數(shù)組作為參數(shù)傳入 useCallback,它將返回該回調(diào)函數(shù)的 memoized 版本,該回調(diào)函數(shù)僅在某個依賴項改變時才會更新。當你把回調(diào)函數(shù)傳遞給經(jīng)過優(yōu)化的并使用引用相等性去避免非必要渲染(例如 shouldComponentUpdate)的子組件時,它將非常有用。

示例

import React, { useState } from "react";
// 子組件
function Childs(props) {
  console.log("子組件渲染了");
  return (
    <>
      <button onClick={props.onClick}>改標題</button>
      <h1>{props.name}</h1>
    </>
  );
}
const Child = React.memo(Childs);
function App() {
  const [title, setTitle] = useState("這是一個 title");
  const [subtitle, setSubtitle] = useState("我是一個副標題");
  const callback = () => {
    setTitle("標題改變了");
  };
  return (
    <div className="App">
      <h1>{title}</h1>
      <h2>{subtitle}</h2>
      <button onClick={() => setSubtitle("副標題改變了")}>改副標題</button>
      <Child onClick={callback} name="桃桃" />
    </div>
  );
}
復制代碼

執(zhí)行結(jié)果如下圖


image.png

當我點擊改副標題這個 button 之后,副標題會變?yōu)椤父睒祟}改變了」,并且控制臺會再次打印出子組件渲染了,這就證明了子組件重新渲染了,但是子組件沒有任何變化,那么這次 Child 組件的重新渲染就是多余的,那么如何避免掉這個多余的渲染呢?

找原因

我們在解決問題的之前,首先要知道這個問題是什么原因?qū)е碌模?/strong>

咱們來分析,一個組件重新重新渲染,一般三種情況:

  1. 要么是組件自己的狀態(tài)改變
  2. 要么是父組件重新渲染,導致子組件重新渲染,但是父組件的 props 沒有改變
  3. 要么是父組件重新渲染,導致子組件重新渲染,但是父組件傳遞的 props 改變

接下來用排除法查出是什么原因?qū)е碌模?/p>

第一種很明顯就排除了,當點擊改副標題 的時候并沒有去改變 Child 組件的狀態(tài);

第二種情況,我們這個時候用 React.memo 來解決了這個問題,所以這種情況也排除。

那么就是第三種情況了,當父組件重新渲染的時候,傳遞給子組件的 props 發(fā)生了改變,再看傳遞給 Child 組件的就兩個屬性,一個是 name,一個是 onClickname 是傳遞的常量,不會變,變的就是 onClick 了,為什么傳遞給 onClick 的 callback 函數(shù)會發(fā)生改變呢?其實在函數(shù)式組件里每次重新渲染,函數(shù)組件都會重頭開始重新執(zhí)行,那么這兩次創(chuàng)建的 callback 函數(shù)肯定發(fā)生了改變,所以導致了子組件重新渲染。

用useCallback解決問題

const callback = () => {
  doSomething(a, b);
}
const memoizedCallback = useCallback(callback, [a, b])
復制代碼

把函數(shù)以及依賴項作為參數(shù)傳入 useCallback,它將返回該回調(diào)函數(shù)的 memoized 版本,這個 memoizedCallback 只有在依賴項有變化的時候才會更新。

那么只需這樣將傳給Child組件callback函數(shù)的改造一下就OK了

const callback = () => { setTitle("標題改變了"); };
// 通過 useCallback 進行記憶 callback,并將記憶的 callback 傳遞給 Child
<Child onClick={useCallback(callback, [])} name="桃桃" />
復制代碼

這樣我們就可以看到只會在首次渲染的時候打印出子組件渲染了,當點擊改副標題和改標題的時候是不會打印子組件渲染了的。

useMemo

概念

const cacheSomething = useMemo(create,deps)

  • create:第一個參數(shù)為一個函數(shù),函數(shù)的返回值作為緩存值。
  • deps: 第二個參數(shù)為一個數(shù)組,存放當前 useMemo 的依賴項,在函數(shù)組件下一次執(zhí)行的時候,會對比 deps 依賴項里面的狀態(tài),是否有改變,如果有改變重新執(zhí)行 create ,得到新的緩存值。
  • cacheSomething:返回值,執(zhí)行 create 的返回值。如果 deps 中有依賴項改變,返回的重新執(zhí)行 create 產(chǎn)生的值,否則取上一次緩存值。

useMemo原理

useMemo 會記錄上一次執(zhí)行 create 的返回值,并把它綁定在函數(shù)組件對應(yīng)的 fiber 對象上,只要組件不銷毀,緩存值就一直存在,但是 deps 中如果有一項改變,就會重新執(zhí)行 create ,返回值作為新的值記錄到 fiber 對象上。

示例

function Child(){
    console.log("子組件渲染了")
    return <div>Child</div> 
}
const Child = memo(Child)
function APP(){
    const [count, setCount] = useState(0);
    const userInfo = {
      age: count,
      name: 'jimmy'
    }
    return <Child userInfo={userInfo}>
}

復制代碼

當函數(shù)組件重新render時,userInfo每次都將是一個新的對象,無論 count 發(fā)生改變沒,都會導致 Child組件的重新渲染。

而下面的則會在 count 改變后才會返回新的對象。

function Child(){
    console.log("子組件渲染了")
    return <div>Child</div> 
}
function APP(){
    const [count, setCount] = useState(0);
    const userInfo = useMemo(() => {
      return {
        name: "jimmy",
        age: count
      };
    }, [count]);
    return <Child userInfo={userInfo}>
}
復制代碼

實際上 useMemo 的作用不止于此,根據(jù)官方文檔內(nèi)介紹:以把一些昂貴的計算邏輯放到 useMemo 中,只有當依賴值發(fā)生改變的時候才去更新。

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

// 計算和的函數(shù),開銷較大
function calcNumber(count) {
  console.log("calcNumber重新計算");
  let total = 0;
  for (let i = 1; i <= count; i++) {
    total += i;
  }
  return total;
}
export default function MemoHookDemo01() {
  const [count, setCount] = useState(100000);
  const [show, setShow] = useState(true);
  const total = useMemo(() => {
    return calcNumber(count);
  }, [count]);
  return (
    <div>
      <h2>計算數(shù)字的和: {total}</h2>
      <button onClick={e => setCount(count + 1)}>+1</button>
      <button onClick={e => setShow(!show)}>show切換</button>
    </div>
  )
}
復制代碼

當我們?nèi)c擊 show切換按鈕時,calcNumber這個計算和的函數(shù)并不會出現(xiàn)渲染了.只有count 發(fā)生改變時,才會出現(xiàn)計算.

useCallback 和 useMemo 總結(jié)

簡單理解呢 useCallback 與 useMemo 一個緩存的是函數(shù),一個緩存的是函數(shù)的返回的結(jié)果。useCallback 是來優(yōu)化子組件的,防止子組件的重復渲染。useMemo 可以優(yōu)化當前組件也可以優(yōu)化子組件,優(yōu)化當前組件主要是通過 memoize 來將一些復雜的計算邏輯進行緩存。當然如果只是進行一些簡單的計算也沒必要使用 useMemo。

我們可以將 useMemo 的返回值定義為返回一個函數(shù)這樣就可以變通的實現(xiàn)了 useCallback。useCallback(fn, deps) 相當于 useMemo(() => fn, deps)

useRef

const refContainer = useRef(initialValue);

useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)。返回的 ref 對象在組件的整個生命周期內(nèi)保持不變

useRef 獲取dom

useRef,它有一個參數(shù)可以作為緩存數(shù)據(jù)的初始值,返回值可以被dom元素ref標記,可以獲取被標記的元素節(jié)點.

import React, { useRef } from "react";
function Example() {
  const divRef = useRef();
  function changeDOM() {
    // 獲取整個div
    console.log("整個div", divRef.current);
    // 獲取div的class
    console.log("div的class", divRef.current.className);
    // 獲取div自定義屬性
    console.log("div自定義屬性", divRef.current.getAttribute("data-clj"));
  }
  return (
    <div>
      <div className="div-class" data-clj="我是div的自定義屬性" ref={divRef}>
        我是div
      </div>
      <button onClick={(e) => changeDOM()}>獲取DOM</button>
    </div>
  );
}
export default Example;
復制代碼
image.png

useRef 緩存數(shù)據(jù)

useRef還有一個很重要的作用就是緩存數(shù)據(jù),我們知道usestate ,useReducer 是可以保存當前的數(shù)據(jù)源的,但是如果它們更新數(shù)據(jù)源的函數(shù)執(zhí)行必定會帶來整個組件從新執(zhí)行到渲染,如果在函數(shù)組件內(nèi)部聲明變量,則下一次更新也會重置,如果我們想要悄悄的保存數(shù)據(jù),而又不想觸發(fā)函數(shù)的更新,那么useRef是一個很棒的選擇。

下面舉一個,每次換成state 上一次值的例子

import React, { useRef, useState, useEffect } from "react";
function Example() {
  const [count, setCount] = useState(0);

  const numRef = useRef(count);

  useEffect(() => {
    numRef.current = count;
  }, [count]);

  return (
    <div>
      <h2>count上一次的值: {numRef.current}</h2>
      <h2>count這一次的值: {count}</h2>
      <button onClick={(e) => setCount(count + 10)}>+10</button>
    </div>
  );
}
export default Example;
復制代碼

當 ref 對象內(nèi)容發(fā)生變化時,useRef不會通知你。變更 .current 屬性不會引發(fā)組件重新渲染。所以,上面的例子中雖然numRef.current的值,已經(jīng)改變了,但是頁面上還是顯示的上一次的值,重新更新時,才會顯示上一次更新的值。

寫在最后

文章出處:https://juejin.cn/post/6993139082054336548

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,908評論 6 541
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,324評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,018評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,675評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,417評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,783評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,779評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,960評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,522評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,267評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,471評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,009評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,698評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,099評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,386評論 1 294
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,204評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,436評論 2 378

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