import React from 'react'; function A() { return ( <h1>魚魚dev</h1> ) }
在這裏咱們並無使用到React變量,那爲何還要引用React進來呢?javascript
能夠試一下,若是咱們省略了React的引入操做import React from 'react';
,就會報如下的錯誤:java
咱們通過babel轉化後,會將上述代碼轉換成:react
function A() { return React.createElement("h1", null, "魚魚dev"); }
因此能夠看出來,JSX只是React.createElement(component, props, ...children)
的語法糖。es6
React一開始的理念是想與瀏覽器的DOM API保持一致,而不是與HTML保持一致。因此更願意選擇DOM API中的className屬性。瀏覽器
這裏提一句,駝峯命名分爲大駝峯和小駝峯,大駝峯爲首字母爲大寫,其他每一個單詞首字母大寫。小駝峯爲首字母小寫,其他每一個單詞首字母小寫。還有另外兩種主流的命名規則,一是下劃線鏈接符,一是橫槓鏈接符。
同上,React的理念是與瀏覽器的DOM API保持一致,也就使用了DOM API中的小駝峯命名的風格。babel
這裏有兩個問題dom
super
?props
?super
? 其實這不是React的限制,而是JavaScript的限制。要想在構造函數裏調用this
,必須得在此以前調用過super。這裏的緣由涉及到了JavaScript的」繼承「。函數
如若沒有調用super:性能
JavaScript是經過原型鏈來實現繼承的,在此咱們不深究原型鏈,單說在原型鏈中super的意義。super指代着父類的構造函數,在子類的構造函數中調用super()
,則意味着調用了父類的構造函數,從而使得建立子類的實例時,不光有子類的屬性,還會有父類的屬性。this
因此說,如過說在子類的構造函數中沒有調用super
的話,則子類的實例中不會有父類的屬性值。這就使得這個繼承名存實亡了。因此JavaScript規定繼承時,必須得在子類的構造函數中調用super
。
props
你必須得在super調用時傳入props
才能在構造函數中使用this.props
,不然使用this.props
會報undefined沒有這個屬性。不過在構造函數以後,如render函數中卻能在其中使用this.props
。
爲何呢?
這是由於在React的構造函數被調用以後,會給建立的React實例對象綁入一個props
屬性,其值就是props
。
const instance = new YourComponent(props); instance.props = props
不過因爲是在構造函數被調用後,才綁如props屬性,也就是說在構造函數執行時,this
是沒有props
這個尚需經的。
因此說,仍是得在super中傳入props,不然就沒法在構造函數中使用this.props
。
class App extends React.Component { constructor (props) { super(props);// 既調用了super,又傳入了props console.log(this.props);// 能夠訪問到值,而且不會報錯 } render () { console.log(this.props);// 能夠訪問到值 return <h1>魚魚dev</h1> } }
class App extends React.Component { constructor (props) { super();// 調用了super,不傳入props console.log(this.props);// undefined } render () { console.log(this.props);// 能夠訪問到值 return <h1>魚魚dev</h1> } }
class App extends React.Component { constructor (props) { // 既不調用super,也不傳入props console.log(this.props);// 這裏就直接報錯了 } render () { console.log(this.props); return <h1>魚魚dev</h1> } }
得益於React中的babel的強大,babel提供了es6中都不支持的實例屬性的寫法,也就是說實例屬性你不光能夠在構造函數中聲明,還能夠像這樣寫:
class A { a = '1' }
而若是用這種寫法,也就不用在類中寫構造函數了。因此繼承也不用手動調用super來繼承父類的實例屬性,默認就幫你調用好了。
class A { a = '1' } class B extends A { b = '2' } console.log(new B().a);// '1'
因此React中能夠這樣寫:
class App extends React.Component { render () { console.log(this.props);// 有值 return <h1>魚魚dev</h1> } }
前面有提到,JSX是React.createComponent(component, props, ...children)
的語法糖,在這裏component
的類型能夠是string或ReactClasstype。
這是在React.createComponent(component, props, ...children)
,而在JSX中是如何區別是string仍是ReactComponent呢?若是是大寫開頭,是ReactComponent,若是是小寫開頭,是string。
function A() { // 小寫開頭,React認爲它是原生dom節點。babel後 // 爲React.createComponent("div",null); return <div></div> }
import MyComponent from './myComponent.js'; function A() { // 大寫開頭,React認爲他是自定義組件。babel後 // 爲React.createComponent(MyComponent,null); return <MyComponent></MyComponent> }
import myComponent from './myComponent.js';// 這裏有個改動,引入自定義組件名小寫開頭 function A() { // 小寫開頭,React認爲它是原生dom節點。babel後 // 爲React.createComponent("myComponent",null); // 但因爲dom節點中沒有myComponent,則報錯 return <myComponent></myComponent> }
若你自己是想用ReactComponent,但卻一小寫開頭:
相信若是你們有研究過JavaScript的this
指向問題的話,都知道像下面這種狀況,函數中的this指向會丟失:
const a = { func: function () { console.log(this); } } const nextA = a.func; nextA();// 打印undefined(嚴格模式下) a.func();// 打印{func: f}
這就是你們常說的this指針丟失的問題。
React中的事件綁定也是這樣的:
class Foo extends React.Component { handleClick () { this.setState({ xxx: aaa }) } render() { return ( <!-- 在這裏我綁定事件未bind(this),結果是當觸發click事件,執行handleClick函數時,內部this指向爲undefined --> <button onClick={this.handleClick}> Click me </button> ) } }
這是由於onClick={this.handleClick}
其實是分爲兩步的:
const handleClick = this.handleClick; ...onClick = handleClick
這就發生了上文所說的this指針丟失。
因此必須得在一開始就肯定死this指向,以保證即便執行了const handleClick = this.handleClick;
`...onClick = handleClick`也不會發現this指針丟失的現象。
具體方法有一下兩種:
class Foo extends React.Component { handleClick () { this.setState({ xxx: aaa }) } render() { return ( // 在綁定的時候再bind(this)。性能不是很好,多處地方調用同一 // 函數的話,得重複bind <button onClick={this.handleClick.bind(this)}> Click me </button> ) } }
class Foo extends React.Component { constructor () { // 在構造函數裏bind(this)。缺點就是寫起來不順手...... // 沒有人會習慣在類裏聲明瞭函數,再去構造函數裏去bind一次把 this.handleClick = this.handleClick.bind(this); } handleClick () { this.setState({ xxx: aaa }) } render() { return ( <button onClick={this.handleClick}> Click me </button> ) } }
除這兩種方法,還有一種方法:箭頭函數能夠解決這一問題(箭頭函數的this指向徹底繼承於上一做用域的this指向),箭頭函數又有兩種寫法:
class Foo extends React.Component { constructor () { // 在構造函數裏bind(this)。缺點就是寫起來不順手...... // 沒有人會習慣在類裏聲明瞭函數,再去構造函數裏去bind一次把 this.handleClick = this.handleClick.bind(this); } handleClick () { this.setState({ xxx: aaa }) } render() { return ( // 至關於每次點擊事件的時候就聲明一個匿名函數,這個比第一種方法還費性能 <button onClick={e => {this.handleClick}}> Click me </button> ) } }
class Foo extends React.Component { // 這是我最喜歡的寫法了,美觀而又省性能 handleClick = () => { this.setState({ xxx: aaa }) } render() { return ( <button onClick={this.handleClick}> Click me </button> ) } }
可能你們會想,爲何React不本身bind呢?由於每次調用的時候,都bind一次,會影響性能,倒不如一開始就bind好,而後在調用時候直接調用。