前面的示例都是渲染的元素,主要是用來闡述ReactDOM.render()工作原理。通常在React項目中是不這樣做的。我們常常會它封裝到一個React組件中,然后再通過ReactDOM.render()把這個組件渲染出來。
- 在React中元素是構成React應用的最小單位。
1.什么是組件
- React是專注于View層的,組件也是React核心理念之一,一個完整的應用將由一個個獨立的組件拼裝而成。React組件可以看成構造出一個虛擬DOM結構的對象。
2.React創(chuàng)建組件的方式
在React中創(chuàng)建組件有三種方式:
- 有狀態(tài)組件(ES6寫法):React.Component
- 有狀態(tài)組件(ES5寫法):React.createClass(注:此方法舊版本react可用,現(xiàn)已不可用)
- 無狀態(tài)組件的函數(shù)寫法(函數(shù)組件)。
3.有狀態(tài)?無狀態(tài)?
- 無狀態(tài)組件,它是一種只負責展示的純組件。這種組件只負責根據(jù)傳入的props來展示,不涉及到要state狀態(tài)、生命周期等操作。
- 有狀態(tài)組件,需要涉及state、生命周期等操作。
- React鼓勵在大型項目中盡可能以無狀態(tài)組件的寫法 來分割原本龐大的組件。
4.React.createClass
注:React.createClass方法現(xiàn)已經不可用,本文章總結只是為了和es6寫法作對比,從而更好的理解。
React.createClass是React剛開始創(chuàng)建組件的方式。這是ES5的原生的JavaScript封裝的函數(shù)來實現(xiàn)的React組件。
動手敲個小例子
我們用一個小例子來了解一下組件的創(chuàng)建的機制。該例子包含一個文本框和一個按鈕,單擊按鈕可以改變文本框的編輯狀態(tài):禁止編輯或允許編輯。并且顯示自定義屬性文本。

var SwitchInput = React.createClass({
getDefaultProps : function () {
return {myattr: "我是默認的屬性"}
}
getInitialState:function(){
return {enable:false}
},
handleClick:function(event){
this.setState({enable:!this.state.enable})
},
render:function(){
return (
<p>
<input type="text" disabled={this.state.enable} />
<button onClick={this.handleClick}>改變textbox狀態(tài)</button>
</p>
)
}
});
ReactDOM.render(<SwitchInput myattr="我是傳過來的屬性"/>, document.getElementById('root'));
state:
- 組件總是需要和用戶互動的。React的一大創(chuàng)新,就是將界面組件看成一個狀態(tài)機,用戶界面擁有不同狀態(tài)并根據(jù)狀態(tài)進行渲染輸出,用戶界面和數(shù)據(jù)始終保持一致。開發(fā)者的主要工作就是定義state,并根據(jù)不同的state渲染對應的用戶界面。
setState()
- React自帶方法。通知React組件數(shù)據(jù)發(fā)生變化的方法是調用成員函數(shù)setState(data,callback)。這個函數(shù)會合并data到this.state,并重新渲染組件。
getInitialState
- 存放state的容器。
props即屬性(Property), 在代碼中寫作 props , 即可用 props 指代 properties .
- 組件的屬性
getDefaultProps
- 存放props的容器
render
- 用于將模板轉為HTML語言,并插入指定的DOM節(jié)點。
props和state的區(qū)別
props是只讀的,不能在組件中修改,只能通過組件傳遞;state只能在所在組件內部更改,或在外部調用setState函數(shù)對狀態(tài)進行間接修改。
在設計組件時,就要想好組件哪些使用state,哪些使用props集合,哪些使用state集合。通常固定的組件內只讀的、由父組件傳遞進來的屬性適合放在props集合中。
5.React.Component
ES6中類的出現(xiàn)改變了我們定義組件的方式,如今,React.createClass已經不可使用,新版本的react創(chuàng)建有狀態(tài)組件都是使用React.component來創(chuàng)建。
我們將上面例子使用es6的方法改寫下。
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
class SwitchInput extends React.Component {
constructor(props) {
super(props)
this.state = {
enable: true
}
this.handleClick = this.handleClick.bind(this) //綁定this
}
handleClick(event) {
this.setState({
enable: !this.state.enable
})
}
render() {
return (
<p>
<input type="text" disabled={this.state.enable}/>
<button onClick={this.handleClick}>
改變輸入框編輯狀態(tài)
</button>
自定義屬性:{this.props.myattr}
</p>
)
}
}
SwitchInput.defaultProps={
myattr: "我是默認的屬性"
}
SwitchInput.propTypes = {
myattr: PropTypes.string
};
ReactDOM.render(<SwitchInput myattr="我是傳過來的屬性"/>, document.getElementById('root'));
- 默認屬性放到defaultProps中
- state值放到constructor構造函數(shù)中。
- prop-types庫是react自帶的屬性類型檢測庫。這里設置myattr為字符串類型,若傳入其他類型,會在控制臺報錯。具體可查看官網。http://www.css88.com/react/docs/typechecking-with-proptypes.html
不清楚constructor以及super等寫法可以看我之前的文章。ES6學習-類(Class)的聲明1
React.createClass與React.Component區(qū)別
根據(jù)上面展示代碼中二者定義組件的語法格式不同之外,二者還有很多重要的區(qū)別,下面就描述一下二者的主要區(qū)別。
- React.Component可以有選擇性的綁定需要的函數(shù),React.createClass會自動綁定函數(shù),這樣會導致不必要的性能開銷。
- 函數(shù)this自綁定
React.createClass創(chuàng)建的組件,其每一個成員函數(shù)的this都有React自動綁定,任何時候使用,直接使用this.method即可,函數(shù)中的this指向類的實例。
const Contacts = React.createClass({
handleClick() {
console.log(this); // React 實例
},
render() {
return (
<div onClick={this.handleClick}></div>
);
}
});
React.Component創(chuàng)建的組件,其成員函數(shù)不會自動綁定this,需要開發(fā)者手動綁定,否則this不能獲取當前組件實例對象。
class Contacts extends React.Component {
constructor(props) {
super(props);
}
handleClick() {
console.log(this); // null
}
render() {
return (
<div onClick={this.handleClick}></div>
);
}
具體綁定方法有三種:
-
在構造函數(shù)中綁定this.
constructor(props) { super(props); this.handleClick = this.handleClick.bind(this); //構造函數(shù)中綁定 } -
直接在結構中綁定
<div onClick={this.handleClick.bind(this)}></div> //使用bind來綁定 -
使用箭頭函數(shù)綁定
<div onClick={()=>this.handleClick()}></div> //使用arrow function來綁定
綁定成功后,這樣在自定義函數(shù)中間就可以使用this了,若不使用this可以不綁定。
6.無狀態(tài)組件
無狀態(tài)組件其實是通過函數(shù)形式或者ES6 arrow function的形式創(chuàng)建的,它是為了創(chuàng)建純展示組件。這種組件只負責根據(jù)傳入的props來展示,不涉及到state狀態(tài)的操作。
function HelloComponent(props) {
return <div>Hello {props.name}</div>
}
ReactDOM.render(<HelloComponent name="react" />, document.getElementById('root')) //Hello react
react鼓勵盡量使用無狀態(tài)組件。其又以下幾個顯著特點:
- 無狀態(tài)組件的創(chuàng)建形式使代碼的可讀性更好,并且減少了大量冗余的代碼,精簡至只有一個render方法,大大的增強了編寫一個組件的便利。
- 組件不會被實例化,無實例化過程也就不需要分配多余的內存,從而整體渲染性能得到提升
- 組件不能訪問this對象。(無狀態(tài)組件由于沒有實例化過程,所以無法訪問組件this中的對象,例如:this.ref、this.state等均不能訪問。若想訪問就不能使用這種形式來創(chuàng)建組件)
- 組件無法訪問生命周期的方法(因為無狀態(tài)組件是不需要組件生命周期管理和狀態(tài)管理)
- 無狀態(tài)組件只能訪問輸入的props,不涉及state等操作。