react、JSX編譯原理、生命週期、屬性、狀態改變、建立組件、複合組件間的信息傳遞、受控和非受控組件、react腳手架

React是Facebook公司研發的一款JS框架(MVC:Model View Controller) 經過數據的改變來影響視圖javascript

一、React腳手架

React是一款框架:具有本身開發的獨立思想 - 劃分組件開發css

前端工程化開發:html

  • 基於框架的組件/模塊化開發
  • 基於webpack的自動部署

webpack來完成以上內容(自動化):前端

  • 基於路由的spa單頁面開發
  • 區分開發環境和生產環境
  • 安裝babel完成ES6編寫代碼(上線時,ES6編譯成ES5)
  • 安裝css、style、file等處理器,處理合並壓縮的
  • 編譯less,sass等預編譯語言
  • 安裝webpack-dev-server ,能夠在開發環境下,編譯後自動建立服務,打開瀏覽器,當代碼修改後,自動保存編譯,頁面自動刷新
  • ....

腳手架 配置webpack相對複雜,咱們須要安裝不少的包,還須要寫不少相對複雜的配置,這時候腳手架應運而生,用來提高咱們開發的效率vue

vue:vue-cli react:create-react-app(應用)java

2、安裝

一、npm install create-react-app -g // 安裝到全局能用命令 (npm root -g 查看全局npm安裝目錄) 二、create-react-app demo1 // 項目名稱demo1,名稱只能(/^[a-z0-9_-]$/)node

腳手架生成目錄中的一些內容:react

一、node_module 當前項目中依賴的包 .bin 本地項目中可執行的命令,在package.json的scripts中配置的對應的腳本便可(還有一個是react-scripts命令) 二、public 存放當前項目的頁面(單頁面應用放index.html便可,多頁面根據本身需求放置須要的頁面)webpack

在react中,全部的邏輯都是在JS中完成的(包括頁面機構的建立),若是想給當前的頁面導入一些css樣式後者img圖片等內容,咱們有兩種方式:ios

(1)、在JS中基於ES6 Module模塊規範,使用import引入,這樣webpack在編譯合併JS的時候,會把導入的資源文件等插入到頁面的機構中(絕對不能在js管控的結構中經過相對目錄./ 或者../ 導入資源,由於在webpack編譯的時候,地址就不在是以前的相對地址要用絕對地址

(2)、若是不想在js中導入(JS中導入的資源最後都是基於webpack編譯),咱們也能夠把資源手動的在html中代入,可是html最後也要基於webpack編譯,導入的地址也不建議寫相對地址,而是使用%PUBLIC_URL%寫成絕對地址

<link rel="manifest" href="%PUBLIC_URL%/reset.min.css">
複製代碼

三、src 項目結構中最主要的目錄,由於後期全部的JS、路由、組件等都是放到這裏面(包括須要編寫的css或者圖片等) index.js 是入口文件 四、.gitignore git的忽略文件 五、package.json 當前項目的配置清單

"dependencies": {
    "react": "^16.4.1",
    "react-dom": "^16.4.1",
    "react-scripts": "1.1.4"
  },
複製代碼

基於腳手架生成工程目錄,自動幫咱們安裝了三個模塊:

  • react 、
  • react-dom、
  • react-scripts(集成了webpack須要的內容babel,css處理,eslint, webpack....,注意:沒有less、sass)

package.json:

"scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts eject"
  }
複製代碼

可執行的腳本

npm run start 或者 yarn start

yarn start

  • 建立一個默認端口號爲3000 ,協議爲http的web服務
  • 按照webpack.config.dev.js把項目編譯
  • 打開瀏覽器預覽咱們的項目
  • 項目修改時候,自動從新編譯,瀏覽器頁面自動刷新,展現最新的效果

yarn build:

  • 基於webpack.config.prod.js 把項目進行編譯打包
  • 生成一個build文件夾,存放最後打包的文件>- 生成一個build文件夾,存放最後打包的文件
  • 部署上線的時候,只須要把build的內容發佈便可

3、React腳手架的深刻剖析

create-react-app 腳手架爲了讓結構目錄清晰,把安裝的webpack及配置文件都集成在了react-scripts模塊中,放到了node_modules中 可是真實項目中,咱們須要在腳手架默認安裝的基礎上,額外安裝一些咱們須要的模塊,例如react-router-domaxios、還有lessless-loader

狀況一:若是咱們安裝其餘的組件,可是安裝成功後不須要修改webpack的配置項,此時咱們直接安裝,調取使用就行,好比react-router-dom 、axios等

狀況二:咱們安裝的插件是基於webpack處理的,也就是須要把安裝的模塊配置到webpack中(從新修改webpack配置項了) 一、首先須要把隱藏到node_module中的配置項暴露到項目中 yarn eject 首先會肯定是否確認執行eject,這個操做不可逆轉,一旦暴露出來配置項,就沒法再隱藏了 若是還有未提交到歷史區的內容,須要先提交,而後才能eject 二、再去修改對應的配置項 暴露後,項目目錄中多了兩個文件夾: config:存放的是webpack的配置文件 (1)webpack.config.dev.js 開發環境下的配置項(yarn start) (2)webpack.config.prod.js 生產環境下的配置項(yarn build) scripts:存放的是可執行腳本的JS文件 (1)start.js: yarn start 執行的就是這個JS (2)build.js: yarn build 執行的就是這.個JS

咱們預覽項目的時候,也是基於webpack編譯,把編譯後的內容放到瀏覽器中運行,因此若是項目中使用了less,咱們須要修改webpack配置項,在配置項中加入less的編譯工做,這樣後期預覽項目,首先基於webpack把less編譯爲css

set HTTPS=true && npm start 開啓HTTPS協議模式 set PORT=1111 && npm start 修改默認端口號

4、漸進式框架

一種漸進式框架設計思想,通常框架中都包含了不少內容,這樣致使框架的體積過於臃腫 拖慢加載的速度, 真實項目中,咱們使用一個框架,不必定用到全部的功能,此時咱們應該把框架的功能進行拆分,用戶想用什麼,讓其本身自由組合便可--"漸進式框架"

全家桶:漸進式框架N多部分的組合 vue全家桶:vue、vue-cli、vue-router、vuex、axios、vue-element 、vant、 react全家桶:react、react-react-app、react-dom、react-router、redux、react-redux、axios、ant、dva、saga、mobx

一、React

react的核心部分,提供了Component類能夠進行組件開發,提供了鉤子函數(生命週期),全部的生命週期函數都是基於回調函數完成的

二、React-dom:

raect獨有的,把JSX語法,渲染爲真實DOM(可以放到頁面中展現的機構都叫作真實的DOM)的組件

react框架都是在JS中進行的,而後經過webpack編譯,再放到瀏覽器中編譯

在index.js這個入口文件:

import React from 'react';
import ReactDOM from 'react-dom';
// import ReactDOM,{render} from 'react-dom';
// 從react-dom中導入一個reactDOM,逗號後面的內容是把ReactDOM這個對象進行結構

let data ='zufeng',
    root = document.querySelector("#root");

ReactDOM.render(<div id="box">hello world!{data}</div>,root,()=>{
    // 回調,通常不用
    let oBox = document.querySelector("#box");
    console.log(oBox.innerHTML);
});
複製代碼

2.一、JSX(也叫react元素):

JSX語法的渲染使用的是ReactDOM.render: ReactDOM.render([jsx],[container],[callback]);

jsx:react獨有的語法, JavaScript+xml(HTML),和咱們以前拼接的字符串相似,都是把html結構代碼和js代碼或者數據混合在一塊兒了,可是他不是字符串 container:容器,咱們想把元素放到頁面中的哪一個容器中 callback:當把容器放到頁面中呈現觸發的回調函數

jsx語法特色:

一、不建議咱們 直接把jsx直接放到body中,而是放在本身建立一個容器中,通常咱們都放在一個id爲root的div中

ReactDOM.render(<section><h2>內容</h2></section>,root)
複製代碼

二、把數據嵌入到jsx中 在JSX中出現的{}是存放JS的,要求JS代碼執行完成須要有返回結果(JS表達式),不能直接放一個對象數據類型的

let name = 'zhufeng'     // 基本數據類型的值
ReactDOM.render(<section><h2{name}</h2></section>,root)

let xx = {name:'xxxx'}
ReactDOM.render(<section><h2{xx}</h2></section>,root)  // 報錯
複製代碼
  • 不能直接放一個對象數據類型的值(對象((除了給style賦值)),數組(若是隻有基本值或者jsx除外),函數都不行)
ReactDOM.render(<ul>
   {
     data.map((item,index)=>{
        return <li key={index}>{item.title}</li>
     })
   }
</ul>,root)
複製代碼
  • 能夠是基本類型的值(布爾類型什麼都不顯示,null,undefined也是jsx元素,表明的是空)
  • 循環判斷語句都不行,可是支持三元運算符

三、循環數組穿件jsx元素,須要給建立的元素設置惟一的key值(當前本次惟一便可) 四、只能出現一個根元素 五、給元素設置樣式類用的是className而不是class 六、style中不能直接寫樣式字符串,須要基於一個樣式對象來遍歷賦值 七、能夠給JSX元素設置屬性: => 屬性值對應大括號中,對象、函數均可以放(也能夠放JS表達式) =>style屬性值必須是對象(不能是字符串)<li style={{color:'#fff'}}></li> =>class 用className代替

ReactDOM.render(<h1 id={'box'} className="box" style={{color:'red'}}>我是標題</h1>);
複製代碼

三、渲染原理(react的核心原理之一)

JSX虛擬DOM變爲真實的DOM(react的核心原理之一)

let  styleObj = {color:'red'};
ReactDOM.render(<h1 id="titleBox" className='title' style={styleObj.color}></h1>)
複製代碼

JSX渲染機制:JSX->真實DOM

一、基於babel babel-loader babel-present-react-app把JSX語法編譯爲React.createElement([type],[props],[children])結構 =>React.createElement中至少有兩參數, type:第一參數的標籤(字符串) props:屬性對象(沒有就是null) 其餘的:都是子元素內容(只要子元素是html,就會變成新的createElement)

var styleObj = { color: 'red' };
ReactDOM.render(React.createElement('h1', { id: 'titleBox', className: 'title', style: styleObj.color }));
複製代碼

二、執行React.createElement(....),建立一個對象(虛擬DOM)

=>key 和ref 都是createElement中的Prop提取出來的 =>props:{ chiledren:存放本身子元素的(沒有子元素就沒有這個屬性),若是有多個子元素,就以數組的形式存儲信息 } 三、ReactDOM.render(JSX語法最後生成的對象,container,callback),基於render方法把生成的對象動態建立爲DOM元素,插入到指定的容器中

四、組件

無論vue仍是react框架,設計之初都是指望咱們按照「組件 / 模塊管理」 的方式來構建程序的,也就是一個程序劃分一個個的組件來單獨管理 src -> component:這個文件夾下存放的就是開發用的組件 【優點】 一、有助於多人協助開發 二、組件能夠複用 ....

react 中建立組件有兩種方式:

一、函數式聲明組件

(1)函數返回結果是一個新的JSX(也就是當前組件的JSX結構) (2)props變量存儲的值是一個對象,包含了調取組件時候傳遞的屬性值,不傳遞的話是個空對象

知識點

createElement遇到一個組件,返回的對象中:type就不是字符串標籤名了,而是一個函數(類),可是屬性仍是存在props中

render渲染的時候,咱們須要作處理:

首先判斷type的類型, 若是是字符串,就建立一個元素標籤, 若是函數或者類,就把函數執行,把props中的每一項(包含children)傳遞給函數 在執行的時候,把函數中return的JSX轉換爲新的對象(經過createElement),把這個對象返回:緊接着render按照以往的渲染方式,建立DOM元素,插入到指定的容器中便可

單閉合和雙閉合組件的區別,雙閉合組件中能夠放子孫元素

函數式聲明特色:

一、會把基於createElement解析出來的對象中的props做爲參數傳遞給組件(能夠完成屢次調取組件傳遞不一樣的信息) 二、一旦組件調取成功,返回的jsx就會渲染到頁面中,可是後期不經過從新調取組件或者獲取DOM元素操做的方式,很難再把渲染好組件中的內容更改 -->"靜態組件"

//Dialog.js
import React from 'react';    // 每一個組件必須引入,由於須要基於它的create-element把JSX進行解析渲染
export default function Dialog(props) {
    //props:調取組件的時候傳遞進來的屬性信息(可能包含className、style、id、可能有children)
    let {con, lx = 0, children,style={}} = props,
        title = lx === 0 ? '系統提示' : '系統警告';
    //children 可能有,可能沒有,多是個值,也多是個數組,每一項多是字符串也多是個對象等,都表明雙閉合組件的子孫元素
    return <section style={style}>
        <h2>{title}</h2>
        <div>{con}</div>
        {/*一、把屬性中的子元素,放到組件中的指定位置*/}
        {/*{children}*/}
        {/*二、也可使用react中專門遍歷children的方法*/}
            {children.map(item => item)}
            {/*// {React.Children.map(children,item=>item)}*/}
        </section>
}

// index.js

import React from 'react';
import ReactDOM from 'react-dom';
// 公共css放index.js中,這樣在其餘組件中也可使用(webpack會把全部的組件最後都編譯到一塊兒,index是主入口)
// import 'static/css/reset.min.css'
import 'bootstrap/dist/css/bootstrap.css'  // 須要導入未通過壓縮的文件,不然報錯(真實項目中bootstrap已是過去式了,後期用ant)

import Dialog from "./component/Dialog-bootstrap";

ReactDOM.render(<main>
    <Dialog content ='馬少帥很帥'/>
    <Dialog type ={2} content='系統錯誤了'/>
    <Dialog type = '請登陸' content={
        '新的JSX語法'
    }>
        <div>
            <input type="text" className='form-control' placeholder='請輸入用戶名'/><br/>
            <input type="password" placeholder='請輸入密碼'/>
        </div>
        <br/>
        <button className='btn btn-success'>登陸</button>
        <button className='btn btn-danger'>取消</button>
    </Dialog>
</main>,root);
複製代碼

二、繼承component類來建立組件

基於component把JSX轉換爲一個對象,當render渲染這個對象的時候,遇到type是一個函數或者類,不是直接建立元素,而是把方法執行,

  • 若是就是函數聲明的組件,就把它當作普通函數執行(方法中的this是undefined),把函數返回的JSX元素(也是解析後的對象)進行渲染
  • 若是是類聲明式的組件,會把當前類new執行,建立類的一個實例(當前本次調用的組件就是它的實例)執行constuctor以後,會執行this.render(),把rende返回的JSX拿過來渲染,因此「類聲明式的組件,必須有一個render的方法,方法中須要返回一個JSX元素」 可是無論哪種方式,最後都會把解析出來的props屬性對象做爲實參傳遞給對應的函數或者類

特色: 一、調取組件至關於建立類的實例(this),把一些私有的屬性掛載到實例上了,這樣組件內容全部的方法中均可以基於實例獲取這些值(包括:傳遞的屬性和本身管理的狀態) 二、有本身的狀態管理,當狀態改變的時候,react會從新渲染視圖(差別更新:基於DOM-DIFF只把有差別的部分渲染)

import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types'  // facebook是公司開發的一個插件,基於這個插件咱們能夠給組件傳的屬性設置規則,設置的規則不會影響頁面的渲染,能夠不加
// 可是會在控制檯拋出警告錯誤

class Dialog extends React.Component{
   // this.props只讀的,咱們沒法在方法中修改它的值,可是能夠給其設置默認值或者設置一些規則(例如:設置是不是必須傳遞的以及傳遞的值的類型等)
   static  defaultProps ={
        lx:"系統提示"
   };
   static propTypes = {
        // 設置屬性規則,若是傳的不是這個規則的,不影響頁面的渲染,只是會在控制檯拋出警告錯誤
        // con: PropTypes.string   傳遞的內容必須是字符串
        con:PropTypes.string.isRequired  // 傳遞的內容是字符串,並且還必須是傳遞
   };
   constructor(props){    // props context updater
       // props:當render渲染而且把當前類執行建立實例的時候,會把以前JSX解析出來的props對象中的信息(可能有children)傳遞給參數props  =>  "調取組件傳遞的屬性"

       // props若是不傳,super也不傳,除了constructor中不能直接使用this.props,其餘聲明周期函數中均可以使用(也就是執行完成constructor,
       // react已經幫咱們把傳遞的屬性接收,而且掛載到實例上了)

       super(props);  // extends繼承,一旦使用了constructor,第一行位置必須設置super執行,至關於React.Component.call(this),也就是call繼承,把父類私有的屬性繼承過來
       // this.props:屬性集合
       // this.refs:ref集合(非受控組件中用到)
       // this.context:上下文

       // - 若是super(props); 在繼承父類私有的時候,就把props掛載到this實例上了,這個this只是constructor中的this,不影響原型上的this,寫不寫都行
       // - 若是隻寫super() 雖然建立實例的時候把屬性傳遞過來了,可是並無傳遞父組件,也就是沒有把屬性掛載到實例上,使用this.props獲取的結果是undefined
       // -
       console.log(props);
       // AA = 12;  設置私有屬性,可是不符合ES6語法,須要babel-preset-react編譯
       // fn=()=>{}  設置一個箭頭函數,可是不符合ES6語法,須要babel-preset-react編譯
   }

   render(){
       // render必須寫還必須有返回的東西
       return <section>
           <h3>系統提示</h3>
           <div>
               zhufeng
           </div>
       </section>
   }
}

ReactDOM.render(<div>
    <Dialog>
        <span>d</span>
    </Dialog>
</div>,root);
複製代碼

組件中的屬性(this.props)是調取組件的時候(建立類實例的時候)傳遞給組件的信息,這部分信息是隻讀的(只能獲取不能修改)-> "組件的屬性是隻讀的"

Object.defineProperty(this.props,'cont',{
   writable:true
});
複製代碼

用這種方法也改不了


組件部分的總結

建立組件有兩種方式:一是「函數式」,一是「建立類式」

函數式

一、操做簡單 二、能實現的功能也很簡單,只是簡單的調取和返回

建立類式

一、操做相對複雜一點,可是也能夠實現更爲複雜的業務功能 二、可以使用生命週期函數操做業務 三、函數式能夠理解爲靜態組件(組件中內容調取的時候,就已經固定了,很難再修改),而類這種方式,能夠基於組件內部的狀態來動態更新渲染的內容:

所謂函數組件是靜態組件,和執行普通方法同樣,調取一次組件,就把組件中內容獲取到,若是不從新調取組件,顯示內容是不發生改變的


【需求】實現頁面上時間的走動

一、函數式的

import React from 'react';
import ReactDOM from 'react-dom';

function Clock() {
  return <div>
      <h3>當前北京時間爲:</h3>
      <div style={{color:'red',fontWeight:'bold'}}>{new Date().toLocaleString()}</div>
  </div>
}
/*每隔一秒從新調取組件*/
setInterval(()=>{
    ReactDOM.render(<Clock/>,root);
},1000)
//適用於組件內容不會再次發生改變的狀況下
複製代碼

二、建立類式

class Clock extends React.Component{
   constructor(){
       super();
       // 初始化組件狀態(都是對象類型):要求咱們在constructor中把後期須要使用的狀態信息所有初始一下(約定俗稱的語法規範)
       this.state = {
           time:new Date().toLocaleString(),
       }
   }
   componentDidMount(){
       //react生命週期函數之一:第一次組件渲染完成後觸發(咱們只須要間隔1000ms把state狀態中的time數據改變,這樣react會幫咱們組件中的部門內容進行渲染)

       setInterval(()=>{
           // this.state.time = new Date().toLocaleString(); //雖然下面的定時器能夠修改狀態,可是不會通知react從新渲染頁面,這樣不行
           //修改組件的狀態
            // 一、修改部分狀態:會用咱們傳遞的對象和初始化的state進行匹配,只把咱們傳遞的屬性進行修改,沒有傳遞的依然保留原始的狀態信息(部分修改)
            // 二、修改狀態修改完成,會通知react把組件進行從新渲染
           
           this.setState({
               time:new Date().toLocaleString(),
           },()=>{
               /*當通知react把須要從新渲染的JSX元素從新渲染完成後,執行的回調操做(相似於生命週期中的componentDidUpdate)項目中通常使用鉤子函數*/
               // 設置回調的緣由是:通知完就直接往下執行,render方法是個異步操做
           });
       },1000)
   }
   render(){
       return <div> <h3>當前北京時間爲:</h3> <div style={{color:'red',fontWeight:'bold'}}>{this.state.time}</div> </div>
   }
}
ReactDOM.render(<Clock/>,root);
複製代碼

React中的組件有兩個很是重要的概念:

一、組件的屬性:[只讀]調取組件的時候傳遞進來的信息 二、組件的狀態:[讀寫]本身在組件中設定和規劃的(只有類聲明式組件纔有狀態的管控你,函數式組件聲明不存在狀態的管理)

組件狀態相似於VUE中的數據驅動:

咱們數據綁定的時候是基於狀態值綁定,當修改組件狀態後,對應的JSX元素也會跟着從新渲染(差別渲染:只把數據改變的部分從新渲染,基於DOM-DIff算法完成)

當代前端框架最重要的核心思想就是:「數據操做視圖(視圖影響數據)」,讓咱們告別JQ手動操做DOM的時代,咱們之後只須要改變數據,框架會幫咱們從新渲染視圖,從而減小直接操做DOM(提升性能,也有助於開發效率)

儘可能少操做DOM

5、React的用法

在react當中: 一、基於數據驅動(修改狀態數據,react幫助咱們從新渲染視圖)完成的組件叫作「受控組件(受數據管控的組件)」 二、基於ref操做DOM實現視圖更新,叫作「非受控組件」 真實項目中,建議多使用「受控組件」

VUE:MVVM 數據更改,視圖跟着改變,視圖更改,數據也跟着改變(雙向數據綁定) React:MVC 數據更改視圖跟着改變(本來是單向的,可是咱們能夠手動設置爲雙向的)

render(){
  let {text} = this.state;

  return <section className='panel panel-default'>
      <div className='panel-heading'>
          <input type="text" className='form-control' value={text} onChange={ev=>{
              // 在onChange中修改狀態信息,實現的是視圖改變數據
              this.setState({
                  text:ev.target.value
              })
          }}/>
      </div>
      <div className='panel-body'>
          {text}
      </div>
  </section>
}
複製代碼

6、生命週期

所謂生命週期函數(鉤子函數)描述一個函數或者組件從建立到銷燬的過程,咱們能夠在過程當中間,基於鉤子函數完成本身的一些操做(例如:在第一次渲染完成作什麼,或者在第二次即將從新渲染以前作什麼等...)

一、基本流程

【基本流程】 constructor: 建立一個組件 componentWillMount: 第一次渲染以前 render:第一次渲染 componentDidMount: 第一次渲染以後 【修改流程】 當組件的狀態數據發生改變(setState)或者傳遞的屬性發生改變(從新調用組件,傳遞不一樣的屬性)都會引起render從新執行渲染(渲染也是差別渲染) shouldComponentUpdate 是否容許組件從新渲染 componentWillUpdate 從新渲染以前 render 第二次及之後從新渲染 componentDidUpdate 從新渲染以後

componentWillReceiveProps 父組件把傳遞給子組件的屬性發生改變後觸發的鉤子函數 屬性改變也會改變子組件從新渲染,觸發鉤子函數

【銷燬】 原有的渲染的不消失,之後不能基於數據改變視圖 componentWillUnmount 卸載組件以前(通常不用)

index.js:

import React from 'react';
import ReactDOM, {render} from 'react-dom';
import PropTypes from 'prop-types';
import 'bootstrap/dist/css/bootstrap.css'

class A extends React.Component {
    static defaultProps = {}; // 第一個執行,屬性設置默認值
    constructor() {
        super();
        console.log('1=constructor');
        this.state = {
            n: 1
        }
    }

    componentWillMount() {
        console.log('3=componentWillMount 第一次渲染前', this.refs.HH);
        // 在這裏,若是直接setState修改數據(同步的),會把狀態信息改變後,而後render和didMount,若是setState是放到一個異步操做中完成(例如:定時器或者從服務器獲取數據),也是先執行render和did
        // 而後再執行這個異步操做修改狀態,緊接着走修改的流程(這樣和放到didMount中沒啥區別),因此咱們通常吧數據請求放到DID中處理
        // 真實項目中的數據綁定,第一次組件渲染,咱們都是綁定的默認屬性,第二次纔是從服務器獲取的數據,有些屬性,咱們須要根據數據是否存在,判斷顯示隱藏
    }

    componentDidMount() {
        console.log('4=componentWillMount 第一次渲染後', this.refs.HH);
        //真實項目中,這個階段通常作以下處理:
        //  一、控制狀態信息更改的操做
        //  二、從服務器獲取數據,而後修改狀態信息,完成數據綁定
        setInterval(() => {
            this.setState({
                n: this.state.n + 1
            })
        }, 5000)
    }

    shouldComponentUpdate(nextProps, nextState) {
        // this.state.n   更新以前的
        console.log('5=shouldComponentUpdate 函數返回true(容許),false(不容許)');
        // return true

        /*在這個鉤子函數中,咱們獲取的state不是最新修改的,而是上一次的state的值
         例如:第一次加載完成後,5000ms後,咱們基於setState把n修改成2,可是此處獲取的仍是1呢
         可是這個有兩個參數:
          nextProps:最新修改的屬性
          nextState:最新修改的狀態
        */

        if (nextState.n > 3) {
            return true
        } else {
            return false
        }
    }

    componentWillUpdate(nextProps, nextState) {
        // this.state.n  也是更新以前的,也有兩個參數存儲最新的信息
        console.log('6=componentWillUpdate');
    }

    componentDidUpdate() {
        // this.state.n   更新以後的
        // 先render
        console.log('8=componentWillUpdate');
    }

    render() {
        console.log('2=render');
        return <section ref='HH'>
            {this.state.n}
        </section>
    }
}

ReactDOM.render(<main>
    <A></A>
</main>, root);
複製代碼

7、複合組件的傳值

父組件傳子組件:

基於屬性傳便可(並且傳遞是單方向的:只能把信息給兒子,兒子不能直接把信息做爲屬性傳遞給父親) 後期子組件中的信息須要修改: 可讓父組件傳給子組件的信息發生變化(也就是子組件接收的屬性發生變化,子組件會從新渲染 => componentWillReceiveProps鉤子函數)

子改父:

相似於這種子改父的操做,咱們須要使用一下技巧: 一、把父組件中一個方法做爲屬性傳遞給子組件 二、在子組件中,把基於屬性傳遞進來的方法,在合適的時候執行(相對於在執行父組件中的方法:而這個方法中徹底能夠操做父組件的信息)

相關文章
相關標籤/搜索