《深入React技術(shù)棧》筆記

一、初入React世界

1.2 JSX語法

  • class 屬性修改為className

  • for 屬性修改為 htmFor

  • 展開屬性
    使用ES6 rest/spread 特性提高效率

const data = { name: 'foo', value : 'bar' };
// const component = <Component name={data.name} value={data.value} />;
const component = <Component {...data}>
  • 自定義HTML 屬性
    如果要使用HTML自定義屬性,要使用data- 前綴
<div data-attr="xxx">content</div>
  • HTML 轉(zhuǎn)義
    dangerouslySetInnerHTML 屬性
<div dangerouslySetInnerHTML={{__html: 'cc &copy:2015'}}></div>

1.3 React 組件

  • props
  1. classPrefix: class前綴。對(duì)于組件來說,定義一個(gè)統(tǒng)一的class前綴,對(duì)樣式與交互分離起了非常重要的作用。
  • 用funtion prop 與父組件通信
  • propTypes
    用于規(guī)范 props 的類型與必需的狀態(tài)

1.5 React 生命周期

React生命周期分成兩類:

  • 當(dāng)組件在掛載或卸載時(shí)
  • 當(dāng)組件接收新的數(shù)據(jù)時(shí),即組件更新時(shí)

推薦初始化組件

import React, { Component, PropTypes } from 'react';
class App extends Component {
    // 類型檢查
    static propTypes = {
        // ...
    };
    // 默認(rèn)類型
    static defaultProps = {
        // ...
    };

    constructor(props) {
        super(props);
        this.state = {
            // ...
        };
    }

    componentWillMount() {
        // ...
    }
    // 在其中使用setState 會(huì)更新組件
    componentDidMount() {
        // ...
    }

    render() {
        return <div>This is a demo.</div>
    }
}

componentWillUnmount 常常會(huì)執(zhí)行一些清理方法

  • 數(shù)據(jù)更新過程
    如果自身的state更新了,那么會(huì)依次執(zhí)行shouldComponentUpdate、componentWillUpdate 、render 和 componentDidUpdate。

如果組件是由父組件更新 props 而更新的,那么在 shouldComponentUpdate 之前會(huì)先執(zhí)行componentWillReceiveProps 方法。

React生命周期整體流程圖

1.6 React與DOM

1.6.1 ReactDOM
其API非常少,只有findDOMNode,unmountComponentAtNode和render

  • findDOMNode
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
  class App extends Component {
     componentDidMount() {
     // this 為當(dāng)前組件的實(shí)例
     const dom = ReactDOM.findDOMNode(this);
   }
   render() {}
} 

findDOMNode只對(duì)已經(jīng)掛載的組件有效
DOM 真正被添加到 HTML 中的生命周期方法是componentDidMount 和 componentDidUpdate 方法

  • render
    把 React 渲染的Virtual DOM 渲染到瀏覽器的 DOM 當(dāng)中,就要使用 render 方法

React 還提供了一個(gè)很少使用的 unmountComponentAtNode 方法來進(jìn)行
卸載操作。

  • refs
    refs即reference,組件被調(diào)用時(shí)會(huì)新建一個(gè)該組件的實(shí)例,而refs就會(huì)指向這個(gè)實(shí)例。

二、漫談React

2.1 事件系統(tǒng)
1、事件委派
React沒有把事件直接綁定在真實(shí)的節(jié)點(diǎn)上,而是綁定在最外層,使用一個(gè)統(tǒng)一的事件監(jiān)聽器,這個(gè)事件監(jiān)聽器上維持了一個(gè)映射來保存所有組件內(nèi)部的事件監(jiān)聽和處理函數(shù)。
React中使用DOM原生事件時(shí),要在組件卸載時(shí)手動(dòng)一處,否則很可能出現(xiàn)內(nèi)存泄漏的問題。

2.2 表單

3.select組件
單選和多選兩種。在JSX語法中,可以通過設(shè)置select標(biāo)簽的 multiple={true}來實(shí)現(xiàn)一個(gè)多選下拉列表。

2.2.2 受控組件

每當(dāng)表單的狀態(tài)發(fā)生變化時(shí),都會(huì)被寫入到組件的state中,這種組件在React中被稱為受控組件(controlled component)。
受控組件更新state的流程:
(1)可以通過在初始 state 中設(shè)置表單的默認(rèn)值
(2)每當(dāng)表單的值發(fā)生變化時(shí),調(diào)用onChange事件處理器
(3)事件處理器通過合成事件對(duì)象e拿到改變后的狀態(tài),并更新state
(4)setState觸發(fā)視圖的重新渲染,完成表單組件值得更新

2.2.3 非受控組件

如果一個(gè)表單組件沒有 value props(單選按鈕和復(fù)選框?qū)?yīng)的是 checked prop)時(shí),就可以稱為非受控組件。相應(yīng)地,也可以使用 defaultValue 和 defaultChecked prop來表示組件的默認(rèn)狀態(tài)。通常,需要通過為其添加ref prop來訪問渲染后的底層DOM元素。

2.3 樣式處理

2.3.3 CSS Modules
CSS Modules 內(nèi)部通過ICSS來解決樣式導(dǎo)入和導(dǎo)出兩個(gè)問題,分別對(duì)應(yīng) :import 和 :export 兩個(gè)新增的偽類

:import("path/to/dep.css") {
  localAlias: keyFromDep;
  /*...*/
}

:export {
  exporteKey: exportedValue;
  /*...*/
}

啟用 CSS Modules

// webpack.config.js
css?modules&localIdentName=[name]_[local]-[hash:base64:5]

加上 modules 即為啟用,其中 localIdentName 是設(shè)置生成樣式的命名規(guī)則

使用webpack可以讓全局樣式和CSS Modules的局部樣式和諧共存

module: {
  loaders: [{
    test: /\.jsx?$/,
    loader: 'babel',  
  }, {
    test: /\.scss$/,
    exclude: path.resolve(__dirname, 'src/styles'),
    loader: 'style!css?modules&localIdentName=[name]_[local]!sass?sourceMap=true',
  },{
    test: /\.scsss$/,
    include: path.resolve(__dirname,'src/styles'),
    loader: 'style!css!sass?sourceMap=true',
  }]
}

2.4 組件間通信

  1. 父組件通過props向子組件傳遞需要的信息。
  2. 子組件向父組件通信
  • 利用回調(diào)函數(shù)
  • 利用自定義事件機(jī)制
  1. 跨級(jí)組件通信
    React中,我們可以使用 context 來實(shí)現(xiàn)跨級(jí)父子組件間的通信
// listItem組件
class ListItem extends Component {
  static contextTypes = {
    color: PropTypes.string,
  };
  render() {
    const { value } = this.props;

    return (
      <li style={{background: this.context.color}}>{value}</li>
    )
  }
 }


// List組件
class List extends Component {
  static childContextTypes = {
    color: PropTypes.string,
  };
  getChildContext() {
    return {
        color: 'red'
    }
  }
}

父組件中定義了 ChildContext,這樣從這一層開始的子組件都可以拿到定義的context。

2.5.2 高階組件

實(shí)現(xiàn)高階組件的方法有如下兩種

  • 屬性代理(props proxy)。高階組件通過被包裹的React組件來操作 props
  • 反向繼承(inheritance inversion)。高階組件繼承于被包裹的React組件
  1. 屬性代理
import React, { Component } from 'react';

const MyContainer = (WrappedComponent) => {
  class extends Component {
    render() {
      return <WrappedComponent {...this.props}>
    }
  }
}

當(dāng)然我們也可以用 decorator 來轉(zhuǎn)換

import React, { Component } from 'react';
@MyContainer
class MyComponent extends Component {
  render();
}

export default MyComponent;

簡單地替換成作用在類上的decorator,即接受需要裝飾的類為參數(shù)。

  • 控制 props
import React, { Component } from 'react';
const MyContainer = (WrappedComponent) => {
  class extends Component {
    render() {
      const newProps = {
         text: newText,
      };
      return <WrappedComponent {...this.props} {...newProps}>
    }
  }
}
  • 通過 refs 使用引用
    高階組價(jià)中,我們可以接受 refs 使用 WrappedComponent 的引用。
import React, { Component } from 'react';
const MyContainer = (WrappedComponent) => {
  class extends Component {
    proc(wrappedComponentInstance) {
      wrappedComponentInstance.method();
    }
    render() {
      const props = Object.assign({}, this.props, {
          ref: this.proc.bind(this),
      });
      return <WrappedComponent {...props}>
    }
  }
}
  • 抽象 state
    抽象一個(gè)input組件
import React, { Componet } from 'react';
const MyContainer = (WrappedComponent) => {
  class extends Component {
    constructor(props) {
      super(props);
      this.state = {
        name:'',
      }

      this.onNameChange = this.onNameChange.bind(this);
    }
  }
 onNameChange(event) {
      this.setState({
          name: event.target.value,
      });
    }

    render() {
      const newProps = {
        name: {
          value: this.state.name,
          onChange: this.onNameChange,
        }
      }
      return <WrappedComponent {...this.props} {...newProps} />
    }
}
  • 使用其他元素包裹 WrappedComponent
import React,{ Component } from 'react';
const MyContainer = (WrappedComponent) => {
  class extends Component {
      render() {
        return (
            <div style={{display: 'block'}}>
              <WrappedComponent {...this.props}>
            </div>
         )
      }
   }
}


// 受控input組件使用
@MyContainer
class MyComponent extends Component {
  render() {
    return <input name="name" {...this.props.name}>
  }
}

高階組件和mixin的不同

mixin與高階組件的區(qū)別.png
  1. 反向繼承
  • 渲染劫持
const MyContainer = (WrappedComponent) => {
  class extends WrappedComponent {
    render() {
      if(this.props.loggedIn) {
        return super.render();
      } else {
        return null;
      }
    }
  }
}

// 實(shí)例二:對(duì)render結(jié)果進(jìn)行修改
const MyContainer = (WrappedComponent) => {
   class extends WrappedComponent {
    render() {
       const elementsTree = super.render();
       let newProps = {};

      if(elementsTree && elementsTree.type === 'input'){
        newProps = {value: 'May the force be with you'};
      }
      const props = Object.assign({}, elementsTree.props, newProps);
      const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.childre);
      return newElementsTree;
     }
   }
}
  • 控制state
const MyContainer = (WrappedComponent) => {
  class extends WrappedComponent {
    render() {
      return (
        <div>
            <h2>HOC Debugger Component</h2>
             <p>Props</p> <pre>{JSON.stringify(this.props, null, 2)}</pre>
             <p>State</p><pre>{JSON.stringify(this.state, null, 2)}</pre>
             {super.render()} 
        </div>
      )
    }
  }
}
  1. 組件命名
  2. 組件參數(shù)
import React, { Component } from 'react';
function HOCFactory(...params) {
  return function HOCFactory(WrappedComponent) {
    return class HOC extends Component {
      render() {
        return <WrappedComponent {...this.props}>
      }
    }
   }
}

// 使用
HOCFactoryFactory(params)(WrappedComponent);
// 或者
@HOCFactoryFactory(params);
class WrappedComponent extends React.Component{}

2.6 組件性能優(yōu)化

  1. 純函數(shù)
  • 給定相同的輸入,它總能返回相同的輸出
  • 過程沒有副作用
  • 沒有額外的狀態(tài)依賴
  1. PureRender
    為重新實(shí)現(xiàn)了 shouldComponentUpdate 生命周期方法,讓當(dāng)前傳入的 props
    和 state 與之前的作淺比較,如果返回 false,那么組件就不會(huì)執(zhí)行 render 方法。

  2. react-addons-perf
    量化所做的性能優(yōu)化效果
    Perf.start()
    Perf.stop()

2.7 動(dòng)畫

TransitionGroup 能幫助我們快捷地識(shí)別出增加或刪除的組件。

React Transition設(shè)計(jì)了以生命周期函數(shù)的方式來實(shí)現(xiàn),即讓子組件的每一個(gè)實(shí)例都實(shí)現(xiàn)相應(yīng)地生命周期函數(shù)。當(dāng)React Transition識(shí)別到某個(gè)子組件增或刪時(shí),則調(diào)用它相應(yīng)地生命周期函數(shù)。我們可以再生命周期函數(shù)中實(shí)現(xiàn)動(dòng)畫邏輯。
如果每一個(gè)子組件的動(dòng)效相同,那么每一個(gè)子組件可以共同用一個(gè)生命周期函數(shù)。因此React Transition 提供了 childFactory 配置,讓用戶自定義一個(gè)封裝子組件的工廠方法,為子組件加上相應(yīng)地生命周期函數(shù)。
React Transition提供的生命周期

  • componentWillAppear
  • componentDidAppear
  • componentWillEnter
  • componentDidEnter
  • componentWillLeave
  • componentDidLeave

componentWillxxx 只要在 componentWillReceiveProps中對(duì)this.props.childrennextProps.children做一個(gè)比較就可以了。componentDidxxx可以在componentWillxxx提供一個(gè)回調(diào)函數(shù),用來執(zhí)行componentDidxxx

React CSS Transition 為子組件的每個(gè)生命周期加了不同的className,這樣用戶可以很方便地根據(jù) className 地變化來實(shí)現(xiàn)動(dòng)畫

<ReactCSSTransitionGroup
  transitionName="example"
  transitionEnterTimeout={400}
>
{items}
</ReactCSSTransitionGroup>

對(duì)應(yīng)地css代碼

.example-enter {
  transform: scaleY(0);
  &.example-enter-active {
    transform: scaleY(1);
    transition: transform .4s ease;
  }
}

使用react-motion實(shí)現(xiàn)一個(gè)spring開關(guān)

import React, {Component} from ''react;

class Switch extends Component {
  constructor(props) {
    super(props);

    this.handleClick = this.handleClick.bind(this);

    this.state = {
      open: false,
    }
  }
  handleClick() {
     this.setState({
      open: !this.state.open
    })
  }
  render() {
    return (
      <Motion style={{x: spring(this.state.open ? 400 : 0)}}>
          {({x}) =>
           <div className="demo">
             <div
               className="demo-block"
               onClick={this.handleClick}
               style={{
                 transform: `translate3d(${x}px, 0, 0)`,
          }}
 />
 </div>
 } 
      </Motion>
    )
  }
}

深入Redux 應(yīng)用框架

5.1 Redux簡介

5.1.2Redux三大原則

  1. 單一數(shù)據(jù)源
  2. 狀態(tài)是只讀地
  3. 狀態(tài)修改均由純函數(shù)完成

5.1.3 Redux 核心API

Redux核心是一個(gè)store,這個(gè)store是由createStore(reducers[,initialState])方法生成

通過createStore方法創(chuàng)建的store是一個(gè)對(duì)象,包含4個(gè)方法

  • getState(): 獲取store中當(dāng)前的狀態(tài)
  • dispatch(action):分發(fā)一個(gè)action,并返回這個(gè)action,這是唯一能改變store中數(shù)據(jù)的方式
  • subscribe(listener): 注冊(cè)一個(gè)監(jiān)聽者,它在store發(fā)生改變時(shí)被調(diào)用
  • replaceReducer(nextReducer): 更新當(dāng)前store里的reducer,一般只會(huì)在開發(fā)模式中調(diào)用該方法。

5.1.4 與React 綁定

需要使用react-redux進(jìn)行react和redux的綁定,其提供了一個(gè)組件和API幫助Redux和React進(jìn)行綁定,一個(gè)是 React組件<Provider />,一個(gè)是 connect(),<Provider />接受一個(gè) store 作為props,它是整個(gè)Redux應(yīng)用的頂層組件,而connect()提供了在整個(gè)React應(yīng)用的任意組件中獲取store中數(shù)據(jù)的功能。

5.2 Redux middleware

Redux 提供了 applyMiddleware 方法來加載 middleware,其源碼如下

import compose from './compose';

export default function applyMiddleware(...middlewares) {
  return (next) => (reducer, initialState) => {
    // 獲取得到原始的store
    let store = next(reducer, initialState);
    let dispatch = store.dispatch;
    // 賦值一個(gè)空數(shù)組,用來存儲(chǔ)后新的dispatch分裂函數(shù)
    let chain = [];

    var middlewareAPI = {
      getState: store.getState,
      dispatch: (action) => dispatch(action)
     };

    chain = middlewares.map(middleware => middleware(middlewareAPI));
    // 將分裂的函數(shù)組合每次都會(huì)執(zhí)行,即每次都執(zhí)行這些中間件函數(shù)
    dispatch = compose(...chain)(store.dispatch);

    return {
      ...store,
      dispath
    }
  }
}

middleware運(yùn)行原理

  1. 函數(shù)式編程思想設(shè)計(jì)
    通過函數(shù)式編程中的 currying。currying 的middleware結(jié)構(gòu)的好處有以下兩點(diǎn)
  • 易串聯(lián):不斷currying形成的middleware可以累積參數(shù),再配合組合方式,很容易形成 pipeline來處理數(shù)據(jù)流
  • 共享store:applyMiddleware執(zhí)行過程中,store還是舊的,applyMiddleware完成后,所有的middleware內(nèi)部拿到的sotore都是最新且相同的
  1. 給middleware分發(fā)store
    let newStore = applyMiddleware(mid1, mid2, mid3)(createStore)(reducer, null);

  2. 組合串聯(lián)middleware
    dispatch = compose(...chain)(store.dispatch)
    Redux中compose的實(shí)現(xiàn)

function compose(...funs) {
  return arg => funs.reduceRight((composed, f) => f((composed), arg))
}

compose(...funcs) 返回的是一個(gè)匿名函數(shù),其中 funcs 就是 chain 數(shù)組。當(dāng)調(diào)用 reduceRight
時(shí),依次從 funcs 數(shù)組的右端取一個(gè)函數(shù) fx 拿來執(zhí)行,fx 的參數(shù) composed 就是前一次 fx+1 執(zhí)
行的結(jié)果,而第一次執(zhí)行的 fn(n 代表 chain 的長度)的參數(shù) arg 就是 store.dispatch。

  1. 在 middleware 中調(diào)用 dispatch 會(huì)發(fā)生什么
Redux middleware流程圖.png

如果這個(gè)middleware粗暴的調(diào)用 store.dispatch(acton),就會(huì)形成無線循環(huán)了。
這里我們就用到了Redux Thunk。
Redux Thunk 會(huì)判斷 action 是否是函數(shù)。如果是,則執(zhí)行 action,否則繼續(xù)傳遞 action 到下一個(gè) middleware。

const tuhun = store => next => action => {
  typeof action === 'function' ?
    action(store.dispatch, store.getState) :
    next(action)
}

5.3 Redux 異步流

5.3.1 使用 middleware 簡化異步請(qǐng)求

  1. redux-thunk
    我們?cè)賮砜纯?redux-thunk 的源代碼:
function createThunkMiddleware(extraArgument) {
 return ({ dispatch, getState }) => next => action => {
   if (typeof action === 'function') {
     return action(dispatch, getState, extraArgument);
   }
   return next(action);
 };

模擬請(qǐng)求天氣的異步請(qǐng)求,action的寫法

function getWeather(url, params) {
   return (dispatch, action) {
    fetch(url, params)
      .then(result => {
        dispatch({
          type: 'GET_WEATHER_SUCCESS',
          payload: result,
        })
      })
      .catch(err => {
        dispatch({
          type: 'GET_WEATHER_ERROR',
          payload: err,
        })
      })
  }
}
  1. redux-promise

import { isFSA } from 'flux-standard-action';
function isPromise(val) {
 return val && typeof val.then === 'function';
}
export default function promiseMiddleware({ dispatch }) {
 return next => action => {
 if (!isFSA(action)) {
 return isPromise(action)
 ? action.then(dispatch)
 : next(action);
 }
 return isPromise(action.payload)
 ? action.payload.then(
 result => dispatch({ ...action, payload: result }),
 error => {
 dispatch({ ...action, payload: error, error: true });
 return Promise.reject(error);
 }
 )
 : next(action);
 };
} 

我們利用 ES7 的 async 和 await 語法,可以簡化上述異步過程:

const fetchData = (url, params) => fetch(url, params);
async function getWeather(url, params) {
 const result = await fetchData(url, params);
 if (result.error) { 
220 第 5 章 深入 Redux 應(yīng)用架構(gòu)
 return {
 type: 'GET_WEATHER_ERROR',
 error: result.error,
 };
 }
 return {
 type: 'GET_WEATHER_SUCCESS',
 payload: result,
 };
} 
  1. redux-saga
    在 Redux 社區(qū),還有一個(gè)處理異步流的后起之秀,名為 redux-saga。它與上述方法最直觀的
    不同就是用 generator 替代了 promise,我們通過 Babel 可以很方便地支持 generator.

Redux 與 路由

我們可以通過 <Router> 、<Route> 這兩個(gè)標(biāo)簽以及一系列屬性
定義整個(gè) React 應(yīng)用的路由方案。

前端開發(fā)熱加載,安裝 webpack-dev-server

npm install -D webpack-dev-server

./node_modules/.bin/webpack-dev-server --hot --inline --content-base

在 mapStateToProps 中,我們從整棵 Redux 狀態(tài)樹中選取了 state.home.list 分支作為當(dāng)前
組件的 props,并將其命名為 list。這樣,在 Home 組件中,就可以使用 this.props.list 來獲取
到所有 PreviewListRedux 中定義的狀態(tài)。
而在 mapDispatchToProps 中,我們從前面提到的 HomeRedux.js 中引入了 listActions,并使
用 Redux 提供的工具函數(shù)將 listActions 中的每一個(gè) action creator(目前只有一個(gè))與 dispatch 進(jìn)
行綁定,最終我們可以在 Home 組件中使用 this.props.listActions 來獲取到綁定之后的 action
creator。

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

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

  • 做React需要會(huì)什么? react的功能其實(shí)很單一,主要負(fù)責(zé)渲染的功能,現(xiàn)有的框架,比如angular是一個(gè)大而...
    蒼都閱讀 14,795評(píng)論 1 139
  • 學(xué)習(xí)必備要點(diǎn): 首先弄明白,Redux在使用React開發(fā)應(yīng)用時(shí),起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,934評(píng)論 10 58
  • 有槽先吐 花了幾天時(shí)間,大致讀完了《深入React技術(shù)棧》,簡單總結(jié)的話,不及預(yù)期。 作者成書前,在知乎開設(shè)pur...
    ronniegong閱讀 4,981評(píng)論 1 8
  • 前言 本文 有配套視頻,可以酌情觀看。 文中內(nèi)容因各人理解不同,可能會(huì)有所偏差,歡迎朋友們聯(lián)系我討論。 文中所有內(nèi)...
    珍此良辰閱讀 11,922評(píng)論 23 111
  • 一個(gè)吃過午飯犯困的午后,加上感冒藥的作用,沒精神。 昨天得知要去外地培訓(xùn)的事情,打破了我的計(jì)劃。設(shè)想了很多的后果,...
    熊貓ii閱讀 324評(píng)論 0 0