您好,登錄后才能下訂單哦!
React 是一個用于構建用戶界面的 JAVASCRIPT 庫。
React 主要用于構建UI,很多人認為 React 是 MVC 中的 V。
React 起源于 Facebook 的內部項目,用來架設 Instagram 的網站,并于 2013 年 5 月開源。
React 擁有較高的性能,代碼邏輯非常簡單,越來越多的人已開始關注和使用它。
React 是解決前端MVC框架中的view視圖層的問題
M 是指數據模型,V是指顯示的問題,C是指控制的問題
1.聲明式設計 ?React采用聲明范式,可以輕松描述應用。
2.高效 ?React通過對DOM的模擬,最大限度地減少與DOM的交互。
3.靈活 ?React可以與已知的庫或框架很好地配合。
4.JSX ? JSX 是 JavaScript 語法的擴展。React 開發不一定使用 JSX ,但我們建議使用它。
5.組件 ? 通過 React 構建組件,使得代碼更加容易得到復用,能夠很好的應用在大項目的開發中。
6.單向響應的數據流 ? React 實現了單向響應的數據流,從而減少了重復代碼,這也是它為什么比傳統數據綁定更簡單。
DOM (文檔對象模型 document object model)
將網頁所有內容映射到一顆樹形結構的層級對象模型上,瀏覽器提供對DOM的支持,用戶可以是用腳本調用DOM,API來動態修改DOM節點,從而達到修改網頁的目的,這種修改是瀏覽器中完成的,瀏覽器會根據DOM的改變來重繪改變的DOM節點部分。
修改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>
<h2>測試程序</h2>
<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)} >{/*此處定義按按鼠標的一個事件,執行這個事件后,調用指定的函數完成對應操作*/}
<h2>flag={text}</h2>
</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)} >{/*此處定義按按鼠標的一個事件,執行這個事件后,調用指定的函數完成對應操作*/}
<h2> flag: {text} name: {this.props.name}</h2>
</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)} >{/*此處定義按按鼠標的一個事件,執行這個事件后,調用指定的函數完成對應操作*/}
<h2> flag: {text} name: {this.props.name} {console.log('parent++++++++++',this.props.parent)} </h2> {/*通過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)} >{/*此處定義按按鼠標的一個事件,執行這個事件后,調用指定的函數完成對應操作*/}
<h2> flag: {text} name: {this.props.name} </h2>
<hr />
<h2>sub:{this.props.children}</h2>
</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)} >
<h2> flag: {text} name: {this.props.name} </h2>
<hr />
<h2>sub:{this.props.children}</h2>
{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)} >{/*此處定義按按鼠標的一個事件,執行這個事件后,調用指定的函數完成對應操作*/}
<h2> flag: {text} </h2>
</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之后調用。
不過,大多數情況向,用不上這些函數,這些鉤子函數是為了精確控制使用。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。