在寫 React 的時候,你可能會寫類似這樣的代碼:
import?React?from?'react'
function?A()?{
?//?...other?code
?return?<h2>前端桃園</h2>
}
復制代碼你肯定疑惑過,上面的代碼都沒有用到 React,為什么要引入 React 呢?
如果你把 import React from ‘react’ 刪掉,還會報下面這樣的錯誤:

那么究竟是哪里用到了這個 React,導致我們引入 React 會報錯呢,不懂這個原因,那么就是 JSX 沒有搞得太明白。
你可以講上面的代碼(忽略導入語句)放到在線 babel 里進行轉化一下,發現 babel 會把上面的代碼轉化成:
function?A()?{
?//?...other?code
?return?React.createElement("h2",?null,?"前端桃園");
}
復制代碼因為從本質上講,JSX 只是為 React.createElement(component, props, ...children) 函數提供的語法糖。
為什么要用 className 而不用 class
React 一開始的理念是想與瀏覽器的 DOM API 保持一直而不是 HTML,因為 JSX 是 JS 的擴展,而不是用來代替 HTML 的,這樣會和元素的創建更為接近。在元素上設置 class 需要使用 className 這個 API:
const?element?=?document.createElement("div")
element.className?=?"hello"?
復制代碼瀏覽器問題,ES5 之前,在對象中不能使用保留字。以下代碼在 IE8 中將會拋出錯誤:
const?element?=?{
?attributes:?{
?class:?"hello"
?}
}?
復制代碼解構問題,當你在解構屬性的時候,如果分配一個 class 變量會出問題:
const?{?class?}?=?{?class:?'foo'?}?//?Uncaught?SyntaxError:?Unexpected?token?}
const?{?className?}?=?{?className:?'foo'?}?
const?{?class:?className?}?=?{?class:?'foo'?}?
復制代碼其他討論可見:有趣的話題,為什么jsx用className而不是class
為什么屬性要用小駝峰
因為 JSX 語法上更接近 JavaScript 而不是 HTML,所以 React DOM 使用 camelCase(小駝峰命名)來定義屬性的名稱,而不使用 HTML 屬性名稱的命名約定。
來自 JSX 簡介
為什么 constructor 里要調用 super 和傳遞 props
這是官網的一段代碼,具體見:狀態(State) 和 生命周期
class?Clock?extends?React.Component?{
?constructor(props)?{
?super(props);
?this.state?=?{date:?new?Date()};
?}
?render()?{
?return?(
?<div>
?<h2>Hello,?world!</h2>
?<h3>It?is?{this.state.date.toLocaleTimeString()}.</h3>
?</div>
?);
?}
}
復制代碼而且有這么一段話,不僅讓我們調用 super 還要把 props 傳遞進去,但是沒有告訴我們為什么要這么做。

不知道你有沒有疑惑過為什么要調用 super 和傳遞 props,接下來我們來解開謎題吧。
為什么要調用 super
其實這不是 React 的限制,這是 JavaScript 的限制,在構造函數里如果要調用 this,那么提前就要調用 super,在 React 里,我們常常會在構造函數里初始化 state,this.state = xxx ,所以需要調用 super。
為什么要傳遞 props
你可能以為必須給 super 傳入 props,否則 React.Component 就沒法初始化 this.props:
class?Component?{
?constructor(props)?{
?this.props?=?props;
?//?...
?}
}
復制代碼不過,如果你不小心漏傳了 props,直接調用了 super(),你仍然可以在 render 和其他方法中訪問 this.props(不信的話可以試試嘛)。
為啥這樣也行?因為React 會在構造函數被調用之后,會把 props 賦值給剛剛創建的實例對象:
const?instance?=?new?YourComponent(props); instance.props?=?props; 復制代碼
props 不傳也能用,是有原因的。
但這意味著你在使用 React 時,可以用 super() 代替 super(props) 了么?
那還是不行的,不然官網也不會建議你調用 props 了,雖然 React 會在構造函數運行之后,為 this.props 賦值,但在 super() 調用之后與構造函數結束之前, this.props 仍然是沒法用的。
//?Inside?React
class?Component?{
?constructor(props)?{
?this.props?=?props;
?//?...
?}
}
//?Inside?your?code
class?Button?extends?React.Component?{
?constructor(props)?{
?super();?//??忘了傳入?props
?console.log(props);?//???{}
?console.log(this.props);?//??undefined
?}
?//?...
}
復制代碼要是構造函數中調用了某個訪問 props 的方法,那這個 bug 就更難定位了。因此我強烈建議始終使用super(props),即使這不是必須的:
class?Button?extends?React.Component?{
?constructor(props)?{
?super(props);?//???We?passed?props
?console.log(props);?//???{}
?console.log(this.props);?//???{}
?}
?//?...
}
復制代碼上面的代碼確保 this.props 始終是有值的。
如果你想避免以上的問題,你可以通過class 屬性提案 來簡化代碼:
class?Clock?extends?React.Component?{
?state?=?{date:?new?Date()};
?render()?{
?return?(
?<div>
?<h2>Hello,?world!</h2>
?<h3>It?is?{this.state.date.toLocaleTimeString()}.</h3>
?</div>
?);
?}
}
復制代碼更詳細的內容可見Dan 的博客
為什么組件用大寫開頭
前面以及說過了,JSX 是 React.createElement(component, props, …children) 提供的語法糖,component 的類型是:string/ReactClass type,我們具體看一下在什么情況下會用到 string 類型,什么情況下用到 ReactClass type 類型
string 類型react會覺得他是一個原生dom節點
ReactClass type 類型 自定義組件
例如(string):在 jsx 中我們寫一個
<div></div> 復制代碼
轉換為js的時候就變成了
React.createElement("div",?null)
復制代碼例如(ReactClass type):在jsx中我們寫一個
function?MyDiv()?{
?return?(<div><div>)
}
<MyDiv></MyDiv>
復制代碼轉換為js的時候就變成了
function?MyDiv()?{
?return?React.createElement("div",?null);
}
React.createElement(MyDiv,?null);
復制代碼上邊的例子中如果將MyDiv中的首字母小寫,如下
function?myDiv()?{
?return?(<div><div>)
}
<myDiv></myDiv>
復制代碼轉換為 js 的時候就變成了
function?myDiv()?{
?return?React.createElement("div",?null);
}
React.createElement("myDiv",?null);
復制代碼由于找不到 myDiv 這個 dom,所以就會報錯。
后記
這是這個系列的第一篇,這些問題也是在我的一個「React交流群」里大家提出來的一些他們剛學 react 的時候容易迷惑的點,下一篇不出意外就是解答以下迷惑的點,如果有其他的問題想知道的,歡迎在評論區留言。

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。