React組件名稱必須以大寫字母開頭 若是組件名稱不以大寫字母開頭,則組件使用將被視爲內置元素,例如div
或span
例如:前端
class greeting extends React.Component{
//...
}
複製代碼
若是嘗試渲染<greeting/>
會報一下警告node
Warning: The tag <greeting> is unrecognized in this browser. If you meant to render a React component, start its name with an uppercase letter.
複製代碼
這裏更大的問題是組件命名爲button
或img
,React會忽略你的組件,只是渲染一個普通Htmlbutton
或者img
標籤。react
用反引號(…)建立的字符串與用單引號('…')建立的字符串不一樣。web
在大多數鍵盤上,可使用 tab 鍵上方的鍵來輸入用反引號( ` )字符。算法
當須要在字符串中包含動態表達式時,使用反引號建立一個字符串(不須要使用字符串鏈接)。mongodb
This is a string template literal that can include expressions
'This is just a string, you cannot include expressions here 複製代碼
假設你想要一個始終報告當前時間的字符串:shell
「Time is ...」數據庫
// Current time string
const time = new Date().toLocaleTimeString();
// 使用普通字符串(單引號或雙引號)時,須要使用字符串鏈接:
'Time is ' + time
// 在使用反引號時,可使用 ${} 在字符串中注入時間
`Time is ${time}`
複製代碼
此外,反引號還聲明一個字符串時,能夠建立一個跨多行的字符串:express
const template = `I
CAN
SPAN
Multiple Lines`;
複製代碼
常規字符串不能這樣作。npm
PropTypes 對象已從 React 中刪除。 其過去是以 React.PropTypes 的形式被使用,但不能再使用它了。
相應的,你須要:
npm install prop-types
import PropTypes from 'prop-types'
複製代碼
而後就可使用它啦,如: PropTypes.string
。
若是你錯誤地使用了 React.PropTypes
,會獲得這樣的錯誤提示:
TypeError: Cannot read property 'string' of undefined
複製代碼
爲了安全起見,請使用主幹版本。 例如,若是教程裏使用的是 React 16,本身就不要使用 React 15 進行開發了。
這對 Node.js 也很重要。若是使用舊版本的 Node,會遇到一系列問題。 例如,若是你正在看一些教程,這些教程使用了 Object.values,而你如今用 Node 6.x,那個版本此方法是不存在的。 你須要 Node 7.x 或更高版本。
你能看出下面的代碼有什麼問題嗎?
class Numbers extends React.Component {
const arrayOfNumbers = _.range(1, 10);
// ...
}
複製代碼
上面的代碼是無效的,由於在 JavaScript 類的內部,不能隨意定義變量,只能使用規定的語法定義方法和屬性。
這有點使人困惑,由於類語法中使用的{}看起來像塊級做用域,但它並非。
在一個由函數構成的組件裏,你就能夠想怎麼搞就怎麼搞:
// Totally Okay:
const Number = (props) => {
const arrayOfNumbers = _.range(1, 10);
// ...
};
複製代碼
你能夠經過 prop 屬性傳遞一個字符串:
<Greeting name="World" />
複製代碼
若是須要傳遞一個數值,不要使用字符串:
// 不要這樣作
<Greeting counter="7" />
複製代碼
相反,使用花括號傳遞一個實際的數值:
<Greeting counter={7} />
複製代碼
在 Greeting 組件中使用 {7},this.props.counter
就被賦值爲數字 7 ,而且能夠對其進行數學運算。 若是將其做爲「7」傳遞,而後將其視爲數字,則可能會遇到意外結果。
要運行 web 服務器,須要使用主機(如 127.0.0.1 )和端口(如 8080)使服務器偵聽有效 http 地址上的請求。
一旦成功運行,web 服務器就佔據了那個端口,你就不能讓這個端口它用,端口會被佔用。
若是你嘗試在另外一個終端上運行相同的服務器,將會獲得端口被佔用的錯誤提示,以下:
Error: listen EADDRINUSE 127.0.0.1:8080
複製代碼
請注意,有時 Web 服務器可能在後臺運行或在分離的屏幕/tmux 會話中運行。你看不到,但它仍然佔據了端口。 要從新啓動服務器,須要「殺死」仍在運行的服務器。
要識別使用某個端口的進程,可使用 ps 之類的命令(以及關於應用程序的grep),或者若是你知道端口號,則可使用 lsof 命令:
lsof -i :8080
有些項目依賴於 shell 環境變量的存在才能啓動。 若是在沒有所需環境變量的狀況下運行這些項目,它們將嘗試爲它們使用未定義的值,並可能會給你一些神祕的錯誤。
例如,若是項目鏈接到像 MongoDB 這樣的數據庫,則可能會使用像 process.env.MONGO_URI這樣的環境變量來鏈接它。 這容許項目與不一樣環境中的不一樣MongoDB 實例一塊兒使用。
要在本地運行鏈接到 MongoDB 的項目,首先必須導出 MONGO_URI 環境變量。 例如,若是你在端口 27017 上運行本地 MongoDB,則須要在運行項目以前執行此操做:
export MONGO_URI="mongodb://localhost:27017/mydb"
複製代碼
你能夠 grep 項目源代碼,找到 process.env 來查清楚其運行正常所須要的環境變量。
不要用:
return {
something();
};
複製代碼
這樣用:
return (
something();
);
複製代碼
第一個將嘗試(而且會失敗)返回一個對象,而第二個將正確調用 something() 函數並返回該函數返回的內容。
由於 JSX 中的任何 都將轉換爲函數調用,因此在返回任何 JSX 時都會出現這個問題。
這個問題在箭頭函數的縮寫語法中也很常見。
不要用:
const Greeting = () => {
<div>
Hello World
</div>
};
複製代碼
這樣用:
const Greeting = () => (
<div>
Hello World
</div>
);
複製代碼
當你使用帶有箭頭函數的中括號時,你就新起了一個函數的做用域。箭頭函數的縮寫語法不用中括號。
代碼部署後可能存在的BUG無法實時知道,過後爲了解決這些BUG,花了大量的時間進行log 調試,這邊順便給你們推薦一個好用的BUG監控工具 Fundebug。
當你想要建立一個返回普通對象的箭頭函數時,上面的花括號和圓括號問題也會讓你感到困惑。
不要用:
const myAction = () => { type: 'DO_THIS' };
複製代碼
這樣用:
const myAction = () => ({ type: 'DO_THIS'});
複製代碼
若是沒有把對象包裹在圓括號裏,你就不能使用縮寫語法。實際上你會給字符串定義一個標籤。
這在 setState 方法的 updater 函數中很常見,由於它須要返回一個對象。 若是要使用箭頭函數語法,則須要用括號包裝該對象。
不要用:
this.setState(prevState => { answer: 42 });
複製代碼
這樣用:
this.setState(prevState => ({ answer: 42 }));
複製代碼
使用 React.Component
,而不是 React.component
。 使用 componentDidMount
,而不是 ComponentDidMount
。使用 ReactDOM
,而不是ReactDom
。
請注意須要的 API 大小寫。 若是使用不正確的大小寫,獲得的錯誤信息可能不會很明確。
從 react 和 react-dom 導入時,確保引入正確的名稱,而且使用的內容與引入徹底相同,ESLint 能夠幫助你指出未使用的內容。
在處理組件屬性時也會遇到這種問題:
<Greeting userName="Max" />
複製代碼
// 在組件內部,你須要使用 props.userName
來獲取傳入的值 若是你沒有使用 props.userName
,而是 props.username
或 props.UserName
,你會至關於用了一個 undefined 的值。須要特別留意下這點,固然更好的是配置 ESLint,它也能指出這些問題。
在類組件中,能夠定義本地 state 對象,而後使用 this 訪問它:
class Greeting extends React.Component {
state = {
name: "World",
};
render() {
return `Hello ${this.state.name}`;
}
}
複製代碼
以上代碼會輸出 「Hello World」。
除 state 以外,你還能夠定義其它本地實例屬性。
class Greeting extends React.Component {
user = {
name: "World",
};
render() {
return `Hello ${this.user.name}`;
}
}
複製代碼
以上代碼也會輸出 「Hello World」。
state 實例屬性是一個特殊屬性,由於 React 會管理它。 你只能經過 setState 更改它,當你這樣作時 React 會作出響應。
然而,定義的全部其餘實例屬性對渲染算法沒有影響。 你能夠根據須要在上面的示例中更改this.user,而且 React 不會在React中觸發渲染機制。
在閉合標籤裏放錯 / 字符。不能否認,有時你可使用 <tag/>
,而其餘時間你須要</tag>
。
在 HTML 中,有一種稱爲「自閉合標籤」(AKA void tag)。這些是表示沒有任何子節點的元素的標記。例如,img 標籤是一個自閉合標籤:
<img src="..." />
複製代碼
// 沒必要使用 <img></img>
div標籤能夠包含子項,所以你可使用開始和結束標記: `
React 項目的流行配置使用 Webpack 和 Babel。 二者都容許使用此特性並將其編譯爲全部瀏覽器都能理解的內容。 只有工做流中有 Webpack 或 Babel 之類的轉譯工具,才能使用 import/export。
可是,在 React 打包應用程序中 import/export 不意味着能夠隨意使用它們! 例如,若是你還經過最新的 Node 進行服務器端渲染,會行不通,你極可能會收到「unexpected token」 錯誤。
要讓 Node 理解 import/export(若是你在前端使用它們就是你須要瞭解它們,而且也想要作 SSR 渲染的話),你須要有能夠編譯其的 Babel preset(像是_env_ preset),才能在Node 端運行。 你能夠在開發時使用像 pm2_、 _nodemon 和 _babel-watch_的工具作到這點,,並在每次更改內容時從新啓動 Node。
我把這個留到最後,由於這是一個大問題,一個很常見的問題。
你能夠在 React 組件中定義類方法,而後在組件的 render 方法中使用它們。 例如:
class Greeting extends React.Component {
whoIsThis() {
console.dir(this); // "this" is the caller of whoIsThis
return "World";
}
render() {
return `Hello ${this.whoIsThis()}`;
}
}
ReactDOM.render(<Greeting />, mountNode);
複製代碼
我在 render 裏以 this.whoIsThis
的方式調用 whoIsThis 方法,由於在 render中,this 關鍵字指的是與表示組件的 DOM 元素關聯的組件實例。
內部 React 確保其類方法中的 「this」 指向實例。 可是,當你使用 whoIsThis 方法的引用時,JavaScript 不會自動綁定實例。
whoIsThis 方法中的 console.dir 能夠正確告訴咱們當前組件實例,由於該方法是使用顯式調用方(this)直接從 render 方法調用的。 執行上面的代碼時,在控制檯中看到Greeting 對象:
然而,當在延遲執行通道,例如事件處理裏執行一樣方法時,調用對象將再也不是顯性的,console.dir 也不會打印當前組件實例。
在上面的代碼中,當單擊字符串時,React 會調用 whoIsThis 方法,但它不會讓你訪問組件實例。 這就是咱們點擊字符串時獲得 undefined 的緣由。 若是類方法須要訪問像this.props 和 this.state 這樣的屬性,這會是一個問題,由於它根本行不通。
對於這個問題有不少解決方案。能夠將方法包裝在內聯函數中,或使用 .bind 來改變 this 指向。 對於不常常更新的組件,二者均可以。
還能夠經過在類的構造函數中而不是在 render 方法中執行來優化 bind 方法。 可是,此方法的最佳解決方案是經過 Babel 來使用 ECMAScript 類字段我(目前仍是stage-3),這樣對於處理程序只需使用箭頭函數就能夠了:
class Greeting extends React.Component {
whoIsThis = () => {
console.dir(this);
}
render() {
return (
<div onClick={this.whoIsThis}>
Hello World
</div>
);
}
}
複製代碼
這樣會和預期同樣執行: