React 是一個用於構建用戶界面的 JAVASCRIPT 庫。
React 主要用於構建UI,不少人認爲 React 是 MVC 中的 V。
React 起源於 Facebook 的內部項目,用來架設 Instagram 的網站,並於 2013 年 5 月開源。
React 擁有較高的性能,代碼邏輯很是簡單,愈來愈多的人已開始關注和使用它。javascript
React 是解決前端MVC框架中的view視圖層的問題
M 是指數據模型,V是指顯示的問題,C是指控制的問題 css
1.聲明式設計 −React採用聲明範式,能夠輕鬆描述應用。html
2.高效 −React經過對DOM的模擬,最大限度地減小與DOM的交互。前端
3.靈活 −React能夠與已知的庫或框架很好地配合。java
4.JSX − JSX 是 JavaScript 語法的擴展。React 開發不必定使用 JSX ,但咱們建議使用它。node
5.組件 − 經過 React 構建組件,使得代碼更加容易獲得複用,可以很好的應用在大項目的開發中。python
6.單向響應的數據流 − React 實現了單向響應的數據流,從而減小了重複代碼,這也是它爲何比傳統數據綁定更簡單。react
DOM (文檔對象模型 document object model)webpack
將網頁全部內容映射到一顆樹形結構的層級對象模型上,瀏覽器提供對DOM的支持,用戶能夠是用腳本調用DOM,API來動態修改DOM節點,從而達到修改網頁的目的,這種修改是瀏覽器中完成的,瀏覽器會根據DOM的改變來重繪改變的DOM節點部分。ios
修改DOM 從新渲染成本過高,前端框架爲了提升效率,應儘可能減小DOM重繪,踢出了virtual DOM,全部的修改如今virtual DOM上完成,經過比較算法,找到瀏覽器DOM之間的差別,使用這個差別操做DOM,瀏覽器只須要渲染這部分的改變就好了。
React 實現了DOM Diff算法能夠高效對比virtual DOM 和 DOM的差別。
JSX 是一種JavaScript和XML混寫的語法,是JavaScript的擴展。
基本結構以下
render( <div> <div> <div>content</div> </div> </div>, document.getElementById('example') );
1 首字母是小寫就是html標記,首字母是大寫就是組件
2 要求嚴格的HTML標記,要求全部標籤都必須閉合,br可應該寫成<br />,/前面要留一個空格
3 單行省略小括號,多行請使用小括號
4 元素有嵌套,建議多行,注意縮進
5 JSX表達式:使用{}括起來,若是大括號內使用了引號,會當作字符串處理,如<div>'2>1?true:flase'{}</div>裏面的表達式就成爲了字符串,結果仍然是此值。
將項目開發基礎文件test.zip解壓。並用這個目錄做爲項目的根目錄,在項目根目錄中,執行下面命令們進行和安裝,安裝完成後,會生成一個node_modules,裏面是安裝的全部依賴的模塊
項目包以下
連接:https://pan.baidu.com/s/1C-ZY9rWU-8ZugE4EwVveWw
提取碼:744p解壓目錄以下
安裝以下
在項目根目錄下執行
npm install
npm init 產生的文件,裏面記錄項目的信息,全部項目依賴。
{ "name": "test", "version": "1.0.0", "description": "magedu blog project", "main": "index.js", "scripts": { //項目管理 "test": "jest", "start": "webpack-dev-server --config webpack.config.dev.js --hot --inline", // start指定啓動webpack的 devserver包,--hot 代表是熱加載,及修改後直接加載 "build": "rimraf dist && webpack -p --config webpack.config.prod.js" // build使用webpack構建打包 }, "repository": {}, //處理版本管理相關,可經過此處進行鏈接git服務器用於提交代碼至git服務器 "author": "zhang", "license": "MIT", "devDependencies": { //開發時依賴,不會打包到目標文件中,對應npm install module-name --save-dev, // babel 轉義,由於開發用了不少的ES6語法,從6.x開始babel拆分紅不少插件,須要什麼引入什麼, "babel-core": "^6.24.1", //核心 "babel-jest": "^19.0.0", "babel-loader": "^6.4.1", //webpack的loader,webpack是基於loader的 "babel-plugin-transform-decorators-legacy": "^1.3.4", "babel-plugin-transform-runtime": "^6.23.0", "babel-preset-env": "^1.4.0", //預設的轉換插件 "babel-preset-react": "^6.24.1", "babel-preset-stage-0": "^6.24.1", "css-loader": "^0.28.0", //css影視相關。包括css-loader,less,less-loader.style-loader "html-webpack-plugin": "^2.28.0", "jest": "^19.0.2", "less": "^2.7.2", "less-loader": "^4.0.3", "react-hot-loader": "^4.3.12", //react熱加載插件,但願改動保存後,直接在頁面上直接反饋出來,不須要手動刷新 "rimraf": "^2.6.2", "source-map": "^0.5.6", //文件打包。js會合並或者壓縮,無法調試,用它來看js源文件是什麼,source-map-loader也是須要webpack的loader "source-map-loader": "^0.2.1", "style-loader": "^0.16.1", "uglify-js": "^2.8.22", "webpack": "^2.4.1", //打包工具 "webpack-dev-server": "^2.4.2" //啓動一個開發的server }, "dependencies": { //運行時依賴,會打包到項目中,對應npm install module-name --save "antd": "^3.10.9", //基於react實現,螞蟻金服開源的react的UI庫, "axios": "^0.16.1", //異步請求支持 "babel-polyfill": "^6.23.0", //解決瀏覽器api不支持問題 "babel-runtime": "^6.23.0", "mobx": "^4.6.0", //狀態管理庫,透明化 "mobx-react": "^5.4.2",// 和react結合的模塊 "react": "^16.6.3", //開發的主框架 "react-dom": "^16.6.3", //支持DOM "react-router": "^4.3.1",// 支持路由 "react-router-dom": "^4.3.1" //DOM綁定路由 } }
.babelrc babel轉義的配置文件
{ "presets": [ "react", "env", "stage-0" ], "plugins": [ "transform-decorators-legacy", "transform-runtime", "react-hot-loader/babel" ] }
webpack.config.dev.js,這是一個符合commonjs的模塊
/** * Created by magedu on 2017/4/20. */ const path = require('path'); const webpack = require('webpack'); module.exports = { //導出 devtool: 'source-map', //導出devtools是source-map entry: { //描述入口,entry 若是是一個字符串,定義就是入口文件,若是是一個數組,裏面包含入口文件,另外一個參數能夠用來配置一個服務器,此處使用熱加載插件,可自動刷新 'app': [ './src/index' ] }, output: { //輸出,輸出目錄是_dirname+'dist',名字叫 bundle.js。 path: path.join(__dirname, 'dist'), filename: 'bundle.js', publicPath: '/assets/' }, resolve: { //指定解析什麼文件類型,這裏設置對js文件解析 extensions: ['.js'] }, module: { rules: [ { test: /\.js$/, exclude: /node_modules/, // node_modules/打包排除目錄。這句話必定要有,不然,編譯就會把這個目錄下全部文件拿進來,此中包含的文件很大 use: [ { loader: 'babel-loader' } //rule中對.js結尾的文件但不在node_modules目錄的文件進行熱加載loader和轉譯babel-loader。 ] }, { test: /\.css$/, use: [ { loader: "style-loader" }, { loader: "css-loader" }, ] }, { test: /\.less$/, use: [ { loader: "style-loader" }, { loader: "css-loader" }, { loader: "less-loader" } ] } ] }, plugins: [ //webpack的插件 new webpack.optimize.OccurrenceOrderPlugin(true), new webpack.HotModuleReplacementPlugin(), new webpack.DefinePlugin({'process.env': {NODE_ENV: JSON.stringify('development')}}) ], devServer: { compress: true, port: 3000, //devserver啓動的端口, publicPath: '/assets/', hot: true,//支持熱加載 inline: true, historyApiFallback: true, stats: { chunks: false }, proxy: { '/api': { //proxy指定/api開頭的路徑都代理到http://127.0.0.1:8000去。 target: 'http://127.0.0.1:8000', changeOrigin: true, pathRewrite: {'^/api':''} } } } };
jsconfig.json 是vscode的配置文件,覆蓋當前配置。
{ "compilerOptions": { "target": "ES6", "module": "commonjs", "experimentalDecorators": true } }
上述是全部相關配置文件解釋,獲取這個文件夾,須要修改name,version,description,須要修改repository倉庫地址,須要修改author,license信息,這些信息修改完成後就能夠開發了。
在項目根目錄使用npm start 啓動devserver便可
npm start
結果以下
上述數字變化的是客戶端一直在執行,其JavaScript腳本在本地執行修改DOM樹,經過DOM樹進行渲染,從而刷新數據
修改/src/index.js中的代碼以下
import React from 'react'; //導入主框架,必需要有 import ReactDom from 'react-dom';//導入react-som,要進行dom樹的操做 class Root extends React.Component{ //組件類定義,從React.Component上繼承,這個類生成JSXElement對象及就是React元素 render() { //渲染函數,返回組件中渲染的內容,注意,此處只能返回惟一一個頂級元素 return <div>hello world </div> } } ReactDom.render(<Root />,document.getElementById('root')); //第一個參數是JSCElement對象,第二個是DOM的Element元素,將React元素添加到DOM的Eelment元素中並進行渲染。還可使用React.createElement建立react元素,第一個參數是React組件或者一個HTML的標籤名稱如(div,span)
修改後代碼以下
import React from 'react'; import ReactDom from 'react-dom'; class Root extends React.Component{ render() { return <div>hello world </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
頁面結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 render() { return <div>Sub class </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
注意 :
1 react 組件的render函數return,只能有一個頂級元素
2 JSX語法是XML,要求全部元素必須閉合,注意<br/>不能寫成<br>
結果以下
測試{}裏面使用引號
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 render() { return <div>{ 1>2?'flase':'true' } {/*此處不是字符串是不行的*/} <hr /> "{ 1>2?'flase':'true'}"{/*此處不是字符串是不行的 此處也是能夠的 */} <hr /> "{ "1>2?'flase':'true'" }"</div>; {/*此處不是字符串是不行的 此處會致使存在衝突*/} } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
每個react組件都有一個狀態變量state,他是一個JavaScript對象,能夠爲其定義屬性來保存值。
若是狀態state發生了變化,會觸發UI的從新渲染
注意: state是組件本身內部使用的,是組件的私有屬性
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { //此處必須是一個對象,此處變化會致使調用render後進行渲染, x: "test", y: ".com" } render() { return <div> {this.state.x + this.state.y} </div> //經過this.stste.xxx來調用此屬性 } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { //此處必須是一個對象,此處變化會致使調用render後進行渲染, x: "test", y: ".com" } render() { this.state.x="test100" //修改屬性 return <div> {this.state.x + this.state.y} </div> //經過this.stste.xxx來調用此屬性 } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { //此處必須是一個對象,此處變化會致使調用render後進行渲染, x: "test", y: ".com" } test() { this.setState({x:"test100"}) } render() { // this.setState({x:"test100"}) //此處不容許在渲染的過程當中修改屬性, // test(); 經過外部定義,內部調用的方式修改也是不能夠的,只能經過異步的方式進行修改,以下 setTimeout(()=>this.setState({x:"test100"}),5000) //定義一個箭頭函數,輸入爲空,輸出爲setState的值,其等待時間爲5S進行刷新修改,此處是異步修改 return <div> {this.state.x + this.state.y} </div> //經過this.stste.xxx來調用此屬性 } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
5s後結果爲:
在項目根目錄中index.html中書寫以下代碼,暫時註釋以前代碼
<html> <head> <script type="text/javascript"> function getEventTrigger(event) { x=event.target; //從事件中獲取元素 alert("觸發的元素的id是:"+x.id) //輸出彈框,並獲取id進行組合 } </script> </head> <body> 測試程序 <div id="test" onmousedown="getEventTrigger(event)"> {/*此處定義鼠標按下,用於觸發事件,並執行對應函數返回對應結果*/} 點擊觸發事件,彈出警示框 </div> </body> </html>
結果以下
點擊下面的,同一行的都會有影響
恢復代碼
在後面的index.js中進行相關配置以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 handleClick(event) { let key =event.target; //獲取傳入參數 alert("觸發的元素的id是:"+key.id) //拋出相關異常 } render() { return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義一個按鼠標事件,執行這個事件後,調用指定的函數完成對應操做*/} 點擊觸發事件,彈出警示框 </div> //經過this.stste.xxx來調用此屬性 } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
點擊以下
添加state用於觸發事件
import React from 'react'; import ReactDom from 'react-dom'; import { runInThisContext } from 'vm'; class Sub extends React.Component{ // 定義子元素 state = { flag:true } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" //此處使用三目運算符用於實現相關功能,當爲true時,返回true,當this.state.flag爲false時返回false return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義按按鼠標的一個事件,執行這個事件後,調用指定的函數完成對應操做*/} flag={text} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub /> {/*引用子元素*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
鼠標點擊true和false 轉換
分析
Sub 類,它有本身的state屬性。當render完成後,網頁上會有一個div標籤,div標籤對象捆綁了一個click事件處理函數,div標籤內有文本內容
若是經過剪輯左鍵,就觸發了click方法關聯的handleClick函數,在這個函數中對狀態值進行修改操做。
狀態值state的改變將引起render的重繪。
若是組件本身的state改變了,只會觸發本身的render方法重繪,此處是state是私有屬性,
注意
{this.handleClick.bind(this)} ,不能外加括號
this.handleClick.bind(this)要綁定this,不然當觸發捆綁的函數時,this是函數執行的上下文決定的,this已經不是觸發事件的對象了,有多是全局對象。所以須要將this傳遞進去使得handleClick可以接受正確的參數。
1 在標籤本級標籤的引用中加入組件的屬性,爲這個組件提供外部屬性name="test",這個屬性會做爲一個單一的對象傳遞給組件,加入到組件的props屬性中。
2 在外部進行添加 parent={this} ,注意這個this是在Root元素中,指的是Root組件自己,能夠在子組件中調用各類方法完成相應的各類操做。
3 在Root中爲使用JSX語法爲Sub增長子元素,這些子元素也會被加入到Sub組件的props.children中
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { flag:true } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" //此處使用三目運算符用於實現相關功能,當爲true時,返回true,當this.state.flag爲false時返回false return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義按按鼠標的一個事件,執行這個事件後,調用指定的函數完成對應操做*/} flag: {text} name: {this.props.name} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub name="test"/> {/*經過在此標籤的調用處傳入相關參數*/} </div> } } ReactDom.render(React.createElement(Root),document.getElementById('root'))
結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { flag:true } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" //此處使用三目運算符用於實現相關功能,當爲true時,返回true,當this.state.flag爲false時返回false return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義按按鼠標的一個事件,執行這個事件後,調用指定的函數完成對應操做*/} flag: {text} name: {this.props.name} {console.log('parent++++++++++',this.props.parent)} {/*經過this.props.parent能夠對ROOT中的各類屬性和方法進行相關的調用操做,如經過this.props.parent.setState()來修改Root的相關組件狀態等操做*/} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub name="test" parent={this}/> {/*經過在此標籤的調用處傳入相關參數,此處的this是Root,此處在誰的區域內此this就是誰 此處是將Root的this指針傳遞進來*/} </div> } } ReactDom.render(<Root />,document.getElementById('root'));
結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { flag:true } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" //此處使用三目運算符用於實現相關功能,當爲true時,返回true,當this.state.flag爲false時返回false return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義按按鼠標的一個事件,執行這個事件後,調用指定的函數完成對應操做*/} flag: {text} name: {this.props.name} <hr /> sub:{this.props.children} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub name="test" parent={this}> {/*經過在此標籤的調用處傳入相關參數,此處的this是Root,此處在誰的區域內此this就是誰 此處是將Root的this指針傳遞進來*/} <div>我是Sub的子標籤</div> </Sub> </div> } } ReactDom.render(<Root />,document.getElementById('root'));
結果以下
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 state = { flag:true } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" return <div id="test" onClick={this.handleClick.bind(this)} > flag: {text} name: {this.props.name} <hr /> sub:{this.props.children} {this.props.parent={}} {/*此處修改屬性,會致使報錯,由於其是隻讀的*/} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub name="test" parent={this}/> </div> } } ReactDom.render(<Root />,document.getElementById('root'));
結果以下
此處提示是隻讀屬性,不能被修改
對外部的修改管不着。如 this.props.parent.setState({x:y}) 能夠修改,此處和python中的元祖相同,若元祖中定義了列表,則雖然元祖是不可變類型,但其中的元素是可變的,仍然是能夠修改的。
使用ES6的構造器,要提供一個參數props,並把這個參數使用super傳遞給父類
import React from 'react'; import ReactDom from 'react-dom'; class Sub extends React.Component{ // 定義子元素 constructor(props) { console.log('props......',props) super(props);//傳遞到父類。其默認在構造中加入了props屬性 this.state={flag:true} //定義flag } handleClick(event) { let key =event.target; //獲取傳入參數 this.setState({flag:!(this.state.flag)}) //當觸發發生時,修改此處的屬性用於下面的顯示操做 } render() { let text=(this.state.flag)?"true":"false" //此處使用三目運算符用於實現相關功能,當爲true時,返回true,當this.state.flag爲false時返回false return <div id="test" onClick={this.handleClick.bind(this)} >{/*此處定義按按鼠標的一個事件,執行這個事件後,調用指定的函數完成對應操做*/} flag: {text} </div> } } class Root extends React.Component{ render() { return <div> hello world <Sub name="test" parent={this}/> </div> } } ReactDom.render(<Root />,document.getElementById('root'));
結果以下
react從 15.0開始支持無狀態組件,定義以下
import ReactDOM from 'react-dom'; import React from 'react'; function Root(props) { return <div>{props.name}</div> } ReactDOM.render(<Root name="test" />,document.getElementById('root'));
結果以下
修改代碼以下
import ReactDOM from 'react-dom'; import React from 'react'; let Root = props => <div>{props.name}</div> ReactDOM.render(<Root name="test" />,document.getElementById('root'));
結果和上面相同
state 是私有屬性,組件外部沒法直接訪問,能夠修改state,但建議使用setState方法。
props是公有public屬性,組件外也能夠訪問,可是是隻讀屬性
組件的聲明週期可分爲三個狀態
1 Mounting:已插入真實DOM
2 Updating:正在被從新渲染
3 Unmounting:已移出真實DOM
1 componentWillMount:在渲染以前調用,在客戶端也在服務端,只會在裝載以前調用一次
2 componentDidMount:在第一次渲染後調用,只在客戶端,以後組件已經生成了對應的DOM結構,能夠經過this.getDOMNode()來進行訪問,若是你想和其餘JavaScript框架一塊兒使用,能夠在這個方法中調用setTimeout,setInterval或者發送AJAX請求等操做(放置異步調用阻塞UI),只在裝載完成後調用一次,在render以後。
這些組件不會在首次render組件的週期調用
1 componentWillReceiveProps(nextProps)在組件接收到一個新的props時被調用,這個方法在初始化render時不會被調用。如上述的經過外部傳入name的狀況會調用此中方式
2 shouldComponentUpdate(nextProps,nextState)返回一個布爾值,在組件接收到新的props或者state時被調用,在初始化時或者使用forceUpdate時不會被調用
做用:
1 能夠在你確認不須要更新組件時使用
2 若是設置爲false,就是不容許更新組件操做。那麼componentWillUpdate,componentWillUpdate不會執行
3 componentWillUpdate(nextProps,nextState)在組件接收到新的props或者state但仍是沒有render時被調用,在初始化時不會被調用
4 componentDidUpdate(prevProps,prevState)在組件完成更新後當即調用,在初始化時不會被調用。
1 componentWillUnmount 在組件從DOM中移除的時候當即被調用
上圖可知,其construtor構造器是最先執行的函數
觸發更新生命週期函數,須要經過更新state和props,
相關代碼以下
import React from 'react'; import ReactDOM from 'react-dom'; class Sub extends React.Component{ constructor(props) { super(props) console.log('sub Constructor') super(props); this.state={count: 0}; //定義變量 } handleClick(event) { this.setState({count:this.state.count+1}); } render(){ console.log('Sub render'); return (<div id='sub' onClick={this.handleClick.bind(this)}> sub's count={this.state.count} </div>) } componentDidMount(){ //第一次render以後 console.log('Sub componentDidMount') } componentWillMount(){ //constructoir以後,第一次調用render console.log('Sub componentWillMount') } componentWillUnmount(){ //清理工做 console.log('Sub componentWillUnmount') } } class Root extends React.Component { constructor(props) { console.log('Root Constructor') super(props); //調用父類對象 this.state={}; // 定義一個對象 } render(){ return (<div>hello world <hr /> <Sub /> </div>); } } ReactDOM.render(<Root/>,document.getElementById('root'));
結果以下
處理過程:父構造---子構造-- componentWillMount ---render----componentDidMount
import React from 'react'; import ReactDOM from 'react-dom'; class Sub extends React.Component{ constructor(props) { super(props) console.log('sub Constructor') super(props); this.state={count: 0}; //定義變量 } handleClick(event) { this.setState({count:this.state.count+1}); } render(){ console.log('Sub render'); return (<div id='sub' onClick={this.handleClick.bind(this)}> sub's count={this.state.count} </div>) } componentDidMount(){ //constructoir以後,第一次調用render console.log('Sub componentDidMount') } componentWillMount(){ //第一次render以後 console.log('Sub componentWillMount') } componentWillUnmount(){ //清理工做 console.log('Sub componentWillUnmount') } componentWillReceiveProps(nextProps) { //props變動時,接到新的props了,交給shouldcompupdate //props 組件內只讀。只能從外部修改 console.log(this.props); console.log(nextProps); console.log('this componentWillReceiveProps',this.state.count) } shouldComponentUpdate(nextProps,nextState) { console.log('Sub shouldComponentUpdate',this.state.count,nextState); return true; //return 爲false將攔截更新 } componentWillUpdate(nextProps,nextState){ // 贊成更新後,真正更新前,執行的動做 console.log('Sub componentWillUpdate',this.state.count,nextState); } componentDidUpdate(prevProps,prevState){ //贊成更新後,真正更新後調用 console.log('Sub componentDidUpdate',this.state.count,prevState); } } class Root extends React.Component { constructor(props) { console.log('Root Constructor') super(props); //調用父類對象 this.state={flag:true,name:'root'}; // 定義一個對象 } handleClick(event) { this.setState( {flag: !this.state.flag, name:this.state.flag?this.state.name.toLowerCase():this.state.name.toUpperCase() // 切換名字大小寫 } ); } render(){ return (<div id='root' onClick={this.handleClick.bind(this)}> my name is {this.state.name}<hr /> <Sub /> {/*父組件的render,會引發下一級組件的更新流程,致使props從新發送,即便子組件props沒有改變過*/} </div>); } } ReactDOM.render(<Root/>,document.getElementById('root'));
結果以下,須要點擊鼠標。下面的顯示和上面的都會動,子組件是鑲嵌在父組件中的,所以其會總體變化。子元素在父元素的區域內的。
相關區域以下
父元素響應區域
子元素響應區域
調用render函數的狀況下也沒刷新,由於發現虛擬DOM和DOM之間是沒有差別的,所以其子區域不須要重繪
點擊父元素,子元素會從新渲染,會受到影響,由於子元素的props會被重置,其是從父元素傳遞過去的,其會從新走一會兒元素走的路。
componentWillMount 第一次裝載,在首次render以前,如控制state,props
componentDidMount 第一次裝載接受,首次render以後,例如控制state,propscomponentWillReceiveProps 在組件內部,props是隻讀不可變的,可是這個函數能夠接受到新的props,能夠對props作一些處理,如this.props={name:'224523542w43'}
componentWillReceiveProps 觸發,也會走shouldComponentUpdate
shouldComponentUpdate判斷是否須要組件更新,就是是否render,精確的控制,提升性能
componentWillUpdate在首次render外,每次render前執行,componentWillUpdate在render以後調用。
不過,大多數狀況向,用不上這些函數,這些鉤子函數是爲了精確控制使用。