快速瞭解react

来源:https://www.cnblogs.com/zhuanzhuanfe/archive/2018/03/18/8596588.html
-Advertisement-
Play Games

概況: 通過本篇文章你可以對react的重點有個整體的認識。 關於react是什麼,優點,解決什麼問題等,網上一大推就不啰嗦了。 瞭解虛擬DOM的實現,參考這篇文章 簡單講,其實就是用一個輕量級的dom結構(用js模擬實現),來模擬重量級的dom結構,通過比對輕量級結構後,在操作重量級dom結構提高 ...


概況:

通過本篇文章你可以對react的重點有個整體的認識。 關於react是什麼,優點,解決什麼問題等,網上一大推就不啰嗦了。 

瞭解虛擬DOM的實現,參考這篇文章 

[虛擬DOM]
(https://www.zhihu.com/question/29504639)

簡單講,其實就是用一個輕量級的dom結構(用js模擬實現),來模擬重量級的dom結構,通過比對輕量級結構後,在操作重量級dom結構提高性能,從而到達性能優化的目的。

生命周期:

快速學習react 先瞭解它的重中之重----生命周期, 一個組件在不同時期會調用不同時期的函數介面也就是對應的生命周期函數

裝載時期的函數

getDefaultProps(是設置預設props)getInitialState(廢棄,設置預設State) 依次執行以下函數 

• constructor

• componentWillMount 

• render 

• componentDidMount

更新時期的函數

如果組件的數據有變化了(porp,state), 依次執行以下函數 

• componentWillReceiveProps 

• shouldComponentUpdate

 • componentWillUpdate

 • render 

• componentDidUpdate

卸載時期的函數

銷毀組件

•componentWillUnmount

1. import React,{ Component } from 'react';
2. class Demo extends Component {
3.  constructor(props) {
4.    // 構造函數,要創造一個組件類的實例,會調用對應的構造函數,
5.    //一個react組件需要構造函數,往往為了兩個目的.
6.    //1:初始化state.2.綁定成員函數this環境。  
7.    // 無狀態的函數就不需要構造函數,
8.      super(props)
9.      console.log("---初始化組件---")
10.      this.state = {
11.        test:'想要顯示一段不一樣的文字'
12.         //定義state,存放頁面的數據,通過this.setState()方法修改
13.        //.this.setState()函數所做的事情,首先是改變this.state的值,然後驅動組件經歷更新過程,這樣才有機會讓this.state里新的值出現在界面上。
14.      }
15.  }
16. componentWillMount () {
17.    console.log("---組件掛載前---最先執行的函數")
18. }
19. componentDidMount () {
20.    console.log("---組件掛載後---")
21. }
22. componentWillReceiveProps (nextProps) {
23.    console.log("---父組件重新渲染---")
24. 值得註意的是,更新時期的componentWillReceiveProps函數,
25. 只要父組件的render函數被調用,在render函數裡面被渲染的子組件就會經歷更新過程,不管父組件傳給子組件的Props有沒有改變,都會觸發子組件的componentWillReceiveProps函數,但是自身的this.setState方法觸發的更新過程不會調用這個函數。
26. }
27. shouldComponentUpdate (nextProps,nextState) {
28.    console.log("---組件接受到重繪狀態---")
29.    它決定了一個組件什麼時候不渲染。
30.    在更新過程中shouldComponemtUpdata 返回 false那就立刻停止更新。
31.    this.setState函數後會執行shouldComponemtUpdata 然後在決定我要不要更新。
32.  相反 shouldComponemtUpdata 函數返回 TRUE,接下來就會依次調用
33.   componentWillUpdata,render,componetDidUpdata函數,它把render像夾心麵包似得夾在了中間。
34. }
35. componentWillUpdate (nextProps,nextState) {
36.  console.log("---組件將要更新---")
37. } 
38. componentDidUpdate (prevProps,prevState) {
39.   console.log("---組件更新完畢---")
40. }
41. render () {
42.    console.log("---組件渲染---")
43.    return (
44.        <div>{this.state.test}</div>
45.    )
46. }
47. componentWillUnmount () {
48.   console.log("---組件銷毀---")
49. }
50. }
51. export default Demo;

 

componentWillMount 和componentDidMount的區別:componentWillMount 可以在伺服器調用,也可以在瀏覽器調用但是componentDidMount只能在瀏覽器被調用,因為裝載是一個組件放到DOM樹上的過程,那麼真正的裝載是不可能在伺服器上完成的,伺服器的渲染並不會產生DOM樹。所以我們可以利用這一點。在componentDidMount被調用時候,組件已經被裝載到DOM樹上了,可放心的去操作渲染出來的任何DOM。

編寫組件:

組件間的傳遞通過props進行傳遞,看下麵例子

   

 import React from 'react';

// 一級父組件

class Level1 extends React.Component{

   render(){

       return  <Level2 color='red'/>

   }

}

// 二級子組件

class Level2 extends React.Component{

   render(){

       return  <Level3 color={this.props.color}/>

   }

}

// 三級孫子組件

class Level3 extends React.Component{

   render(){

       return  <div color={{color: this.props.color}}/>

   }

}

 

也可以這樣創建

  1. import React from 'react';
    
    const Level1 = React.createClass({  
    
     render() {
    
       return (
    
         <div></div>
    
       );
    
     }
    
    });
    
    export default Level1 ;  

     

React.createClass和extends Component的區別:

Component{}是ES6的寫法,會自動繼承Component裡面的屬性 createClass({})是React的ES5寫法,會生成一個React Component 語法區別 

• propType 和 getDefaultProps 

• 狀態的區別 

• this區別 

• Mixins

 參考這篇文章 

[React.createClass和extends Component的區別]
(https://segmentfault.com/a/1190000005863630)

 如果你的組件是無狀態的,純輸出組件也可以直接寫成函數如下

  1. function Pure(props){
    
      return(
    
          <div>{props.xxxx}</div>
    
      )
    
    }

     

react 組件必須一級一級傳遞 ,如果想要越級傳遞,1直接到5,那麼需要用到redux

 

redux

redux之前最好瞭解下flux,但是redux更加優秀。 react和redux事實上是兩個獨立的東西,如果你兩者單獨使用推薦react-redux庫,我們從redux 使用方法開始,循序漸進過渡到react-redux,這個庫可以讓我們簡化代碼的書寫

在redux框架下,一個react組件是這樣運行的

讀取Store的狀態,用於初始化組件的狀態,同時監聽Store的狀態改變,當Store狀態發生改變時候,就需要更新組件的狀態,從而驅動渲染。當需要更新store狀態時,就要派發action對象。 根據當前props,和state,渲染用戶界面。

項目結構

actions--->用戶行為 components--->組件 containers--->容器 reducer--->一個純函數返回新的state狀態 store--> store裡面負責分發action行為 index.html ---> 模板文件 webpack---> 打包配置文件

actions:

• 是一個行為的抽象

 • 是普通JS對象 

• 一般由方法生成

 • 必須有一個type 我要添加一本書這個行為可以如下:

  1. const addTodo = (text) =>{
    
       retrun {
    
          type:'Add',
    
          id: nextTodoId++,
    
          text,
    
       }
    
    }

     

reducer: 

• 是響應的抽象 

• 是純方法 

• 傳入舊的狀態和action 

• 返回新的狀態

簽名函數:reducer(state, action) state 是當前狀態,action是接受到的action, 註意不能改變參數state和action

  1. const todo = (state, action) =>{
    
       switch (action.type){
    
       case "Add_Book":
    
        return
    
         {
    
             text: action.text,
    
        }
    
    }

     

用一個例子串起來:

設計一個具有加減功能的項目:

Actions.js:

export const increment = (counterCaption) => {

 return {

   type: increment,

   counterCaption: counterCaption

 };

};

 

export const decrement = (counterCaption) => {

 return {

   type: decrement,

   counterCaption,//es6寫法等同於counterCaption: counterCaption

 };

};

Reducer.js:

export default (state, action) => {

 const {counterCaption} = action;//等同於const counterCaption= action.counterCaption;

 

 switch (action.type) {

   case increment:

     return {...state, [counterCaption]: state[counterCaption] + 1};

   case decrement:

     return {...state, [counterCaption]: state[counterCaption] - 1};

 

   default:

     return state

 }

}

 

//return {...state, [counterCaption]: state[counterCaption] - 1};等同於

//const newState = Object.assign({},state);

//newState[counterCaption]--;

//return newState;

 

Store.js:

import {createStore} from 'redux';

import reducer from './Reducer.js';

 

const initValues = {

 'First': 0,

 'Second': 10,

 'Third': 20

};

 

const store = createStore(reducer, initValues);

 

export default store;

 

//createStore是redux庫提供的函數第一個參數是更新狀態的reducer,第二參數是初始值

 

views(容器):

import React, { Component } from 'react';

import Counter from './Counter.js';

 

class ControlPanel extends Component {

 render() {

   return (

     <div>

       <Counter caption="First" />

       <Counter caption="Second" />

       <Counter caption="Third" />

     </div>

   );

 }

}

export default ControlPanel;

 

Counter.js(組件):

import React, { Component, PropTypes } from 'react';

 

import store from '../Store.js';

import * as Actions from '../Actions.js';

 

const buttonStyle = {

 margin: '10px'

};

 

class Counter extends Component {

 render() {

   const {caption, onIncrement, onDecrement, value} = this.props;

 

   return (

     <div>

       <button style={buttonStyle} onClick={onIncrement}>+</button>

       <button style={buttonStyle} onClick={onDecrement}>-</button>

       <span>{caption} count: {value}</span>

     </div>

   );

 }

}

//以下是對參數類型的定義,開啟eslint需要寫一下代碼。

Counter.propTypes = {

 caption: PropTypes.string.isRequired,//表示caption是string類型,必填

 onIncrement: PropTypes.func.isRequired,

 onDecrement: PropTypes.func.isRequired,

 value: PropTypes.number.isRequired

};

 

 

class CounterContainer extends Component {

 constructor(props) {

   super(props);

 

   this.onIncrement = this.onIncrement.bind(this);

   this.onDecrement = this.onDecrement.bind(this);

   this.onChange = this.onChange.bind(this);

   this.getOwnState = this.getOwnState.bind(this);

 

   this.state = this.getOwnState();

 }

 

 getOwnState() {

   return {

     value: store.getState()[this.props.caption]

   };

 }

 

 onIncrement() {

   store.dispatch(Actions.increment(this.props.caption));

 }

 

 onDecrement() {

   store.dispatch(Actions.decrement(this.props.caption));

 }

 

 onChange() {

  //為了保持Store上的狀態和this.state的同步

   this.setState(this.getOwnState());

 }

 

 shouldComponentUpdate(nextProps, nextState) {

   return (nextProps.caption !== this.props.caption) ||

     (nextState.value !== this.state.value);

 }

 

 componentDidMount() {

  //為了保持Store上的狀態和this.state的同步

   store.subscribe(this.onChange);

 }

 

 componentWillUnmount() {

   //為了保持Store上的狀態和this.state的同步

   store.unsubscribe(this.onChange);

 }

 

 render() {

//Counter 在上面

   return <Counter caption={this.props.caption}

     onIncrement={this.onIncrement}

     onDecrement={this.onDecrement}

     value={this.state.value} />

 }

}

 

CounterContainer.propTypes = {

 caption: PropTypes.string.isRequired

};

 

export default CounterContainer;

 

通常我們會把容器放在container文件夾下,把組件放在component下 

ControlPanel 根本就沒有使用store,如果僅僅為了傳遞prop給組件counter就要求支持state prop,顯然不合理,其中react提供了Context的功能可以解決這個問題;

Context:

我們增加Provider.js,代碼如下:

import {PropTypes, Component} from 'react';

 

class Provider extends Component {

 

 getChildContext() {

   return {

     store: this.props.store

   };

 }

 render() {

   return this.props.children; //Provider包裹的子元素輸出出來

 }

}

 

Provider.contextTypes = {

 store: PropTypes.object

}

export default Provider;

 

index.js 文件引入Provider

import React from 'react';

import ReactDOM from 'react-dom';

import ControlPanel from './views/ControlPanel';

import store from './Store.js';

import Provider from './Provider.js';

ReactDOM.render(

 <Provider store={store}>

   <ControlPanel />

 </Provider>,

 document.getElementById('root')

);

 

最後我們在修改ControlPanel中的Counter組件, 

React-Redux:

如果理解上面的例子之後你會發現有些復用的部分可以提取出來,各個組件關心自己的部分就行了,react-redux庫就是解決這個事情的,讓你開發爽到飛起

react-redux 規定,所有的 UI 組件都由用戶提供,容器組件則是由 React-Redux 自動生成。也就是說,用戶負責視覺層,狀態管理則是全部交給它。

首先我們先瞭解一下重要的函數connect,React-Redux 提供connect方法,用於從 UI 組件生成容器組件,就是將這兩種組件連起來。 connect方法的完整 API

import { connect } from 'react-redux'

const VisibleTodoList = connect(

 mapStateToProps,

 mapDispatchToProps

)(TodoList)

 

connect方法接受兩個參數:mapStateToProps和mapDispatchToProps。它們定義了 UI 組件的業務邏輯。前者負責輸入邏輯,即將state映射到 UI 組件的參數(props),後者負責輸出邏輯,即將用戶對 UI 組件的操作映射成 Action。

此時index.js文件變成:

import React from 'react';

import ReactDOM from 'react-dom';

import {Provider} from 'react-redux';

 

import ControlPanel from './views/ControlPanel';

import store from './Store.js';

ReactDOM.render(

 <Provider store={store}>

   <ControlPanel/>

 </Provider>,

 document.getElementById('root')

);

//Provider在根組件外麵包了一層,這樣一來,App的所有子組件就預設都可以拿到state了

 

Counter.js文件變成

import React, { PropTypes } from 'react';

import * as Actions from '../Actions.js';

import {connect} from 'react-redux';

 

const buttonStyle = {

 margin: '10px'

};

 

function Counter({caption, onIncrement, onDecrement, value}) {

 return (

   <div>

     <button style={buttonStyle} onClick={onIncrement}>+</button>

     <button style={buttonStyle} onClick={onDecrement}>-</button>

     <span>{caption} count: {value}</span>

   </div>

 );

}

 

Counter.propTypes = {

 caption: PropTypes.string.isRequired,

 onIncrement: PropTypes.func.isRequired,

 onDecrement: PropTypes.func.isRequired,

 value: PropTypes.number.isRequired

};

 

function mapStateToProps(state, ownProps) {

 return {

   value: state[ownProps.caption]

 }

}

 

function mapDispatchToProps(dispatch, ownProps) {

 return {

   onIncrement: () => {

     dispatch(Actions.increment(ownProps.caption));

   },

   onDecrement: () => {

     dispatch(Actions.decrement(ownProps.caption));

   }

 }

}

 

export default connect(mapStateToProps, mapDispatchToProps)(Counter);

 

connect函數實際上是個高階函數,瞭解可以參考這邊文章 

[Higher-Order Components](https://reactjs.org/docs/higher-order-comonents.html)

關於react 路由可以參考這邊文章 

[路由](http://www.ruanyifeng.com/blog/2016/05/react_router.html?utm_source=tool.lu)

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • GitHub地址(歡迎下載完整Demo) https://github.com/ganchuanpu/AOPDemo 項目需求描述 我想類似於這樣的個人中心的界面,大家都不會陌生吧。那幾個有箭頭的地方都是可以點擊進行頁面跳轉的,但是需要先判斷用戶是否登錄,如果已經登錄,則正常跳轉,如果沒有登錄,則跳 ...
  • 第3章 計劃3.1 初始探索 在項目開始時,開發人員會和客戶商討一下關於新系統的情況,以確定出所有真正重要的信息。然而,他們不會試圖去確定所有的特性。隨著項目的進展,客戶會不斷的發現新的特性。特性發現的過程會一直持續到項目完成。 當識別出一個特性時,會把它分解成一個或者多個用戶故事,並把這些用戶故事 ...
  • vscode是微軟開發的的一款代碼編輯器,就如官網上說的一樣,vscode重新定義(redefined)了代碼編輯器。當前市面上常用的輕型代碼編輯器主要是:sublime,notepad++,editplus,atom這幾種。比起notepad++、editplus,vscode集成了許多IDE才具 ...
  • vue 點我 ... ...
  • 腳本語言最重要的幾個部分: 數據類型 運算符 控制語句 數組 方法(函數) 一、基礎知識 關鍵字:系統定義 有意義的名字如 background link 等 標識符:自己定 比如class的名字aa 變數:可以看作儲存數據的容器,名字必須用字母開頭,對大小寫敏感。定義後可多次賦值 傳值賦值。 定義 ...
  • 1.寫HTML 訪問方式: http://localhost:8080/myweb/hellow.html (註意:8080埠要加上) 本地電腦:(HP-PC) D:\tomact\webapps\myweb(網頁寫到這裡) ...
  • 上圖是今天下午5個小時的解決成果 1:安裝軟體要耐心,此次安裝軟體第一個星期安裝時正常是可以用的接著不能用了第二個星期,然後我天天就想為什麼,其實不然也沒事嗎,可能軟體太多導致, 最終感覺還是基礎功不牢固而導致的;第二個星期天最後一天的晚上19.32裝好的; 2.開始安裝,對於我們開發者來說java ...
  • 一、什麼是緩存 一個緩存就是一個組件,它可以透明地存儲數據,以便未來可以更快地服務於請求。 緩存能夠服務的請求越多,整體系統性能就提升得越多。 二、Angular 中的緩存 2.1 $cacheFactory 簡介 $cacheFactory 是一個為所有Angular服務生成緩存對象的服務。在內部 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...