學(xué)習(xí) React.js 比你想象的要簡單
通過 Medium 中的一篇文章來學(xué)習(xí) React.js 的基本原理

你有沒有注意到在 React 的 logo 中隱藏著一個六角星?只是順便提下...
去年我寫了一本簡短的關(guān)于學(xué)習(xí) React.js 的書,有 100 頁左右。今年,我要挑戰(zhàn)自己 —— 將其總結(jié)成一篇文章,并向 Medium 投稿。
這篇文章不是講什么是 React 或者 你該怎樣學(xué)習(xí) React。這是在面向那些已經(jīng)熟悉了 JavaScript 和 DOM API 的人的 React.js 基本原理介紹
本文采用嵌入式 jsComplete 代碼段,所以為了方便閱讀,你需要一個合適的屏幕寬度。
下面所有的代碼都僅供參考。它們也純粹是為了表達(dá)概念而提供的例子。它們中的大多數(shù)有更好的實(shí)踐方式。
您可以編輯和執(zhí)行下面的任何代碼段。使用 Ctrl+Enter 執(zhí)行代碼。每一段的右下角有一個點(diǎn)擊后可以在 jsComplete/repl 進(jìn)行全屏模式編輯或運(yùn)行代碼的鏈接。
1 React 全部都是組件化的
React 是圍繞可重用組件的概念設(shè)計的。你定義小組件并將它們組合在一起形成更大的組件。
無論大小,所有組件都是可重用的,甚至在不同的項目中也是如此。
React 組件最簡單的形式,就是一個普通的 JavaScript 函數(shù):
function Button (props) {
// 這里返回一個 DOM 元素,例如:
return <button type="submit">{props.label}</button>;
}
// 將按鈕組件呈現(xiàn)給瀏覽器
ReactDOM.render(<Button label="Save" />, mountNode)
例 1:編輯上面的代碼并按 Ctrl+Enter 鍵執(zhí)行(譯者注:譯文暫時沒有這個功能,請訪問原文使用此功能,下同)
括號中的 button 標(biāo)簽將稍后解釋。現(xiàn)在不要擔(dān)心它們。
ReactDOM
也將稍后解釋,但如果你想測試這個例子和所有接下來的例子,上述render
函數(shù)是必須的。(React 將要接管和控制的是ReactDOM.render
的第 2 個參數(shù)即目標(biāo) DOM 元素)。在 jsComplete REPL 中,你可以使用特殊的變量mountNode
。
例 1 的注意事項:
- 組件名稱首字母大寫,
Button
。必須要這樣做是因為我們將處理 HTML 元素和 React 元素的混合。小寫名稱是為 HTML 元素保留的。事實(shí)上,將 React 組件命名為 “button” 然后你就會發(fā)現(xiàn) ReactDOM 會忽略這個函數(shù),僅僅是將其作為一個普通的空 HTML 按鈕來渲染。 - 每個組件都接收一個屬性列表,就像 HTML 元素一樣。在 React 中,這個列表被稱為屬性。雖然你可以將一個函數(shù)隨意命名。
- 在上面 Button 函數(shù)組件的返回輸出中,我們奇怪地寫了段看上去像 HTML 的代碼。這實(shí)際上既不是 JavaScript 也不是 HTML,老實(shí)說,這甚至不是 React.js。然而它非常流行,以至于成為 React 應(yīng)用程序中的默認(rèn)值。這就是所謂的 JSX,這是一個JavaScript 的擴(kuò)展。JSX 也是一個折中方案!繼續(xù)嘗試并在上面的函數(shù)中返回其他 HTML 元素,看看它們是如何被支持的(例如,返回一個文本輸入元素)。
2 JSX 輸出的是什么?
上面的例 1 可以用沒有 JSX 的純 React.js 編寫,如下:
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
// 要使用 Button,你可以這么做
ReactDOM.render(
React.createElement(Button, { label: "Save" }),
mountNode
);
例 2:不使用 JSX 編寫 React 組件
在 React 頂級 API 中,createElement
函數(shù)是主函數(shù)。這是你需要學(xué)習(xí)的 7 個 API 中的 1 個。React 的 API 就是這么小。
就像 DOM 自身有一個 document.createElement 函數(shù)來創(chuàng)建一個由標(biāo)簽名指定的元素一樣,React 的 createElement
函數(shù)是一個高級函數(shù),有和 document.createElement
同樣的功能,但它也可以用于創(chuàng)建一個表示 React 組件的元素。當(dāng)我們使用上面例 2 中的按鈕組件時,我們使用的是后者。
不像 document.createElement
,React 的 createElement
在接收第二個參數(shù)后,接收一個動態(tài)參數(shù),它表示所創(chuàng)建元素的子元素。所以 createElement
實(shí)際上創(chuàng)建了一個樹。
這里就是這樣的一個例子:
const InputForm = React.createElement(
"form",
{ target: "_blank", action: "https://google.com/search" },
React.createElement("div", null, "Enter input and click Search"),
React.createElement("input", { className: "big-input" }),
React.createElement(Button, { label: "Search" })
);
// InputForm 使用 Button 組件,所以我們需要這樣做:
function Button (props) {
return React.createElement(
"button",
{ type: "submit" },
props.label
);
}
// 然后我們可以通過 .render 方法直接使用 InputForm
ReactDOM.render(InputForm, mountNode);
例 3:React 創(chuàng)建元素的 API
上面例子中的一些事情值得注意:
-
InputForm
不是一個 React 組件;它僅僅是一個 React 元素。這就是為什么我們可以在ReactDOM.render
中直接使用它并且可以在調(diào)用時不使用<InputForm />
的原因。 - React.createElement 函數(shù)在前兩個參數(shù)后接收了多個參數(shù)。從第3個參數(shù)開始的參數(shù)列表構(gòu)成了創(chuàng)建元素的子項列表。
- 我們可以嵌套
React.createElement
調(diào)用,因為它是 JavaScript。 - 當(dāng)這個元素不需要屬性時,React.createElement 的第二個參數(shù)可以為空或者是一個空對象。
- 我們可以在 React 組件中混合 HTML 元素。你可以將 HTML 元素作為內(nèi)置的 React 組件。
- React 的 API 試圖和 DOM API 一樣,這就是為什么我們在 input 元素中使用
className
代替class
的原因。我們都希望如果 React 的 API 成為 DOM API 本身的一部分,因為,你知道,它要好得多。
上述的代碼是當(dāng)你引入 React 庫的時候瀏覽器是怎樣理解的。瀏覽器不會處理任何 JSX 業(yè)務(wù)。然而,我們更喜歡看到和使用 HTML,而不是那些 createElement
調(diào)用(想象一下只使用 document.createElement
構(gòu)建一個網(wǎng)站!)。這就是 JSX 存在的原因。取代上述調(diào)用 React.createElement
的方式,我們可以使用一個非常簡單類似于 HTML 的語法:
const InputForm =
<form target="_blank" action="https://google.com/search">
<div>Enter input and click Search</div>
<input className="big-input" name="q" />
<Button label="Search" />
</form>;
// InputForm “仍然”使用 Button 組件,所以我們也需要這樣。
// JXS 或者普通的表單都會這樣做
function Button (props) {
// 這里返回一個 DOM 元素。例如:
return <button type="submit">{props.label}</button>;
}
// 然后我們可以直接通過 .render 使用 InputForm
ReactDOM.render(InputForm, mountNode);
例 4:為什么在 React 中 JSX 受歡迎(和例 3 相比)
注意上面的幾件事:
- 這不是 HTML 代碼。比如,我們?nèi)匀豢梢允褂?
className
代替class
。 - 我們?nèi)栽诳紤]怎樣讓上述的 JavaScript 看起來像是 HTML。看一下我在最后是怎樣添加的。
我們在上面(例 4)中寫的就是 JSX。然而,我們要將編譯后的版本(例 3)給瀏覽器。要做到這一點(diǎn),我們需要使用一個預(yù)處理器將 JSX 版本轉(zhuǎn)換為 React.createElement
版本。
這就是 JSX。這是一種折中的方案,允許我們用類似 HTML 的語法來編寫我們的 React 組件,這是一個很好的方法。
“Flux” 在頭部作為韻腳來使用,但它也是一個非常受歡迎的 應(yīng)用架構(gòu),由 Facebook 推廣。最出名的是 Redux,F(xiàn)lux 和 React 非常合適。
JSX,可以單獨(dú)使用,不僅僅適用于 React。
3 你可以在 JavaScript 的任何地方使用 JSX
在 JSX 中,你可以在一對花括號內(nèi)使用任何 JavaScript 表達(dá)式。
const RandomValue = () =>
<div>
{ Math.floor(Math.random() * 100) }
</div>;
// 使用:
ReactDOM.render(<RandomValue />, mountNode);
例 5:在 JSX 中使用 JavaScript 表達(dá)式
任何 JavaScript 表達(dá)式可以直接放在花括號中。這相當(dāng)于在 JavaScript 中插入 ${}
模板。
這是 JSX 內(nèi)唯一的約束:只有表達(dá)式。例如,你不能使用 if
語句,但三元表達(dá)式是可以的。
JavaScript 變量也是表達(dá)式,所以當(dāng)組件接受屬性列表時(不包括 RandomValue
組件,props
是可選擇的),你可以在花括號里使用這些屬性。我們在上述(例 1)的 Button
組件是這樣使用的。
JavaScript 對象也是表達(dá)式。有些時候我們在花括號中使用 JavaScript 對象,這看起來像是使用了兩個花括號,但是在花括號中確實(shí)只有一個對象。其中一個用例就是將 CSS 樣式對象傳遞給響應(yīng)中的特殊樣式屬性:
const ErrorDisplay = ({message}) =>
<div style={ { color: 'red', backgroundColor: 'yellow' } }>
{message}
</div>;
// 使用
ReactDOM.render(
<ErrorDisplay
message="These aren't the droids you're looking for"
/>,
mountNode
);
例 6:一個對象傳遞特殊的 React 樣式參數(shù)
注意我解構(gòu)的只是在屬性參數(shù)之外的信息。這只是 JavaScript。還要注意上面的樣式屬性是一個特殊的屬性(同樣,它不是 HTML,它更接近 DOM API)。我們使用一個對象作為樣式屬性的值并且這個對象定義樣式就像我們使用 JavaScript 那樣(我們可以這樣做)。
你可以在 JSX 中使用 React 元素。因為這也是一個表達(dá)式(記住,一個 React 元素只是一個函數(shù)調(diào)用):
const MaybeError = ({errorMessage}) =>
<div>
{errorMessage && <ErrorDisplay message={errorMessage} />}
</div>;
// MaybeError 組件使用 ErrorDisplay 組件
const ErrorDisplay = ({message}) =>
<div style={ { color: 'red', backgroundColor: 'yellow' } }>
{message}
</div>;
// 現(xiàn)在我們使用 MaybeError 組件:
ReactDOM.render(
<MaybeError
errorMessage={Math.random() > 0.5 ? 'Not good' : ''}
/>,
mountNode
);
例 7:一個 React 元素是一個可以通過 {} 使用的表達(dá)式
上述 MaybeError
組件只會在有 errorMessage
傳入或者另外有一個空的 div
才會顯示 ErrorDisplay
組件。React 認(rèn)為 {true}
、 {false}
{undefined}
和 {null}
是有效元素,不呈現(xiàn)任何內(nèi)容。
我們也可以在 JSX 中使用所有的 JavaScript 的集合方法(map
、reduce
、filter
、 concat
等)。因為他們返回的也是表達(dá)式:
const Doubler = ({value=[1, 2, 3]}) =>
<div>
{value.map(e => e * 2)}
</div>;
// 使用下面內(nèi)容
ReactDOM.render(<Doubler />, mountNode);
例 8:在 {} 中使用數(shù)組
請注意我是如何給出上述 value
屬性的默認(rèn)值的,因為這全部都只是 JavaScript。注意我只是在 div 中輸出一個數(shù)組表達(dá)式。React 是完全可以的。它只會在文本節(jié)點(diǎn)中放置每一個加倍的值。
4 你可以使用 JavaScript 類寫 React 組件
簡單的函數(shù)組件非常適合簡單的需求,但是有的時候我們需要的更多。React 也支持通過使用 JavaScript 類來創(chuàng)建組件。這里 Button
組件(在例 1 中)就是使用類的語法編寫的。
class Button extends React.Component {
render() {
return <button>{this.props.label}</button>;
}
}
// 使用(相同的語法)
ReactDOM.render(<Button label="Save" />, mountNode);
例 9:使用 JavaScript 類創(chuàng)建組件
類的語法是非常簡單的:定義一個擴(kuò)展的 React.Component
類(另一個你需要學(xué)習(xí)的 React 的頂級 API)。該類定義了一個單一的實(shí)例函數(shù) —— render()
,并使函數(shù)返回虛擬 DOM 對象。每一次我們使用基于類的 Button
組件(例如,通過 <Button ... />
),React 將從這個基于類的組件中實(shí)例化對象,并在 DOM 樹中使用該對象。
這就是為什么上面的例子中我們可以在 JSX 中使用 this.props.label
渲染輸出的原因,因為每一個組件都有一個特殊的稱為 props
的 實(shí)例 屬性,這讓所有的值傳遞給該組件時被實(shí)例化。
由于我們有一個與組件的單個使用相關(guān)聯(lián)的實(shí)例,所以我們可以按照自己的意愿定制該實(shí)例。例如,我們可以通過使用常規(guī) JavaScript 構(gòu)造函數(shù)來構(gòu)造它:
class Button extends React.Component {
constructor(props) {
super(props);
this.id = Date.now();
}
render() {
return <button id={this.id}>{this.props.label}</button>;
}
}
// 使用
ReactDOM.render(<Button label="Save" />, mountNode);
例 10:自定義組件實(shí)例
我們也可以定義類的原型并且在任何我們希望的地方使用,包括在返回的 JSX 輸出的內(nèi)部:
class Button extends React.Component {
clickCounter = 0;
handleClick = () => {
console.log(`Clicked: ${++this.clickCounter}`);
};
render() {
return (
<button id={this.id} onClick={this.handleClick}>
{this.props.label}
</button>
);
}
}
// 使用
ReactDOM.render(<Button label="Save" />, mountNode);
例 11:使用類的屬性(通過單擊保存按鈕進(jìn)行測試)
注意上述例 11 中的幾件事情
-
handleClick
函數(shù)使用 JavaScript 新提出的 class-field syntax 語法。這仍然是 stage-2,但是這是訪問組件安裝實(shí)例(感謝箭頭函數(shù))最好的選擇(因為很多原因)。然而,你需要使用類似 Babel 的編譯器解碼為 stage-2(或者僅僅是類字段語法)來讓上述代碼工作。 jsComplete REPL 有預(yù)編譯功能。
// 錯誤:
onClick={this.handleClick()}
// 正確:
onClick={this.handleClick}
5 React 中的事件:兩個重要的區(qū)別
當(dāng)處理 React 元素中的事件時,我們與 DOM API 的處理方式有兩個非常重要的區(qū)別:
- 所有 React 元素屬性(包括事件)都使用 camelCase 命名,而不是 lowercase。例如是
onClick
而不是onclick
。 - 我們將實(shí)際的 JavaScript 函數(shù)引用傳遞給事件處理程序,而不是字符串。例如是
onClick={handleClick}
而不是onClick="handleClick"
。
React 用自己的對象包裝 DOM 對象事件以優(yōu)化事件處理的性能,但是在事件處理程序內(nèi)部,我們?nèi)匀豢梢栽L問 DOM 對象上所有可以訪問的方法。React 將經(jīng)過包裝的事件對象傳遞給每個調(diào)用函數(shù)。例如,為了防止表單提交默認(rèn)提交操作,你可以這樣做:
class Form extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
console.log('Form submitted');
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
}
// 使用
ReactDOM.render(<Form />, mountNode);
例 12:使用包裝過的對象
6 每一個 React 組件都有一個故事:第 1 部分
以下僅適用于類組件(擴(kuò)展 React.Component
)。函數(shù)組件有一個稍微不同的故事。
- 首先,我們定義了一個模板來創(chuàng)建組件中的元素。
- 然后,我們在某處使用 React。例如,在
render
內(nèi)部調(diào)用其他的組件,或者直接使用ReactDOM.render
。 - 然后,React 實(shí)例化一個對象然后給它設(shè)置 props 然后我們可以通過
this.props
訪問。這些屬性都是我們在第 2 步傳入的。 - 因為這些全部都是 JavaScript,
constructor
方法將會被調(diào)用(如果定義的話)。這是我們稱之為的第一個:組件生命周期方法。 - 接下來 React 計算渲染之后的輸出方法(虛擬 DOM 節(jié)點(diǎn))。
- 因為這是 React 第一次渲染元素,React 將會與瀏覽器連通(代表我們使用 DOM API)來顯示元素。這整個過程稱為 mounting。
- 接下來 React 調(diào)用另一個生命周期函數(shù),稱為
componentDidMount
。我們可以這樣使用這個方法,例如:在 DOM 上做一些我們現(xiàn)在知道的在瀏覽器中存在的東西。在此生命周期方法之前,我們使用的 DOM 都是虛擬的。 - 一些組件的故事到此結(jié)束,其他組件得到卸載瀏覽器 DOM 中的各種原因。在后一種情況發(fā)生時,會調(diào)用另一個生命周期的方法,
componentWillUnmount
。 - 任何 mounted 的元素的狀態(tài)都可能會改變。該元素的父級可能會重新渲染。無論哪種情況,mounted 的元素都可能接收到不同的屬性集。React 的魔力就是這兒,我們實(shí)際上需要的正是 React 的這一點(diǎn)!在這一點(diǎn)之前,說實(shí)話,我們并不需要 React。
- 組價的故事還在繼續(xù),但是在此之前,我們需要理解我所說的這種狀態(tài)。
7 React 組件可以具有私有狀態(tài)
以下只適用于類組件。我有沒有提到有人叫表象而已的部件 dumb?
狀態(tài)類是任何 React 類組件中的一個特殊字段。React 檢測每一個組件狀態(tài)的變化,但是為了 React 更加有效,我們必須通過 React 的另一個 API 改變狀態(tài)字段,這就是我們要學(xué)習(xí)的另一個 API —— this.setState
:
class CounterButton extends React.Component {
state = {
clickCounter: 0,
currentTimestamp: new Date(),
};
handleClick = () => {
this.setState((prevState) => {
return { clickCounter: prevState.clickCounter + 1 };
});
};
componentDidMount() {
setInterval(() => {
this.setState({ currentTimestamp: new Date() })
}, 1000);
}
render() {
return (
<div>
<button onClick={this.handleClick}>Click</button>
<p>Clicked: {this.state.clickCounter}</p>
<p>Time: {this.state.currentTimestamp.toLocaleString()}</p>
</div>
);
}
}
// 使用
ReactDOM.render(<CounterButton />, mountNode);
例 13:setState 的 API
這可能是最重要的一個例子因為這將是你完全理解 React 基礎(chǔ)知識的方式。這個例子之后,還有一些小事情需要學(xué)習(xí),但從那時起主要是你和你的 JavaScript 技能。
讓我們來看一下例 13,從類開始,總共有兩個,一個是一個初始化的有初始值為 0
的 clickCounter
對象和一個從 new Date()
開始的 currentTimestamp
。
另一個類是 handleClick
函數(shù),在渲染方法中我們給按鈕元素傳入 onClick
事件。通過使用 setState
的 handleClick
方法修改了組件的實(shí)例狀態(tài)。要注意到這一點(diǎn)。
另一個我們修改狀態(tài)的地方是在一個內(nèi)部的定時器,開始在內(nèi)部的 componentDidMount
生命周期方法。它每秒鐘調(diào)用一次并且執(zhí)行另一個函數(shù)調(diào)用 this.setState
。
在渲染方法中,我們使用具有正常讀語法的狀態(tài)上的兩個屬性(沒有專門的 API)。
現(xiàn)在,注意我們更新狀態(tài)使用兩種不同的方式:
- 通過傳入一個函數(shù)然后返回一個對象。我們在
handleClick
函數(shù)內(nèi)部這樣做。 - 通過傳入一個正則對象,我們在在區(qū)間回調(diào)中這樣做。
這兩種方式都是可以接受的,但是當(dāng)你同時讀寫狀態(tài)時,第一種方法是首選的(我們這樣做)。在區(qū)間回調(diào)中,我們只向狀態(tài)寫入而不讀它。當(dāng)有問題時,總是使用第一個函數(shù)作為參數(shù)語法。伴隨著競爭條件這更安全,因為 setstate
實(shí)際上是一個異步方法。
我們應(yīng)該怎樣更新狀態(tài)呢?我們返回一個有我們想要更新的的值的對象。注意,在調(diào)用 setState
時,我們?nèi)慷紡臓顟B(tài)中傳入一個屬性或者全都不。這完全是可以的因為 setState
實(shí)際上 合并 了你通過它(返回值的函數(shù)參數(shù))與現(xiàn)有的狀態(tài),所以,沒有指定一個屬性在調(diào)用 setState
時意味著我們不希望改變屬性(但不刪除它)。
8 React 將要反應(yīng)
React 的名字是從狀態(tài)改變的反應(yīng)中得來的(雖然沒有反應(yīng),但也是在一個時間表中)。這里有一個笑話,React 應(yīng)該被命名為Schedule!
然而,當(dāng)任何組件的狀態(tài)被更新時,我們用肉眼觀察到的是對該更新的反應(yīng),并自動反映了瀏覽器 DOM 中的更新(如果需要的話)。
將渲染函數(shù)的輸入視為兩種:
- 通過父元素傳入的屬性
- 以及可以隨時更新的內(nèi)部私有狀態(tài)
當(dāng)渲染函數(shù)的輸入改變時,輸出可能也會改變。
React 保存了渲染的歷史記錄,當(dāng)它看到一個渲染與前一個不同時,它將計算它們之間的差異,并將其有效地轉(zhuǎn)換為在 DOM 中執(zhí)行的實(shí)際 DOM 操作。
9 React 是你的代碼
您可以將 React 看作是我們用來與瀏覽器通信的代理。以上面的當(dāng)前時間戳顯示為例。取代每一秒我們都需要手動去瀏覽器調(diào)用 DOM API 操作來查找和更新 p#timestamp
元素,我們僅僅改變組件的狀態(tài)屬性,React 做的工作代表我們與瀏覽器的通信。我相信這就是為什么 React 這么受歡迎的真正原因;我們只是不喜歡和瀏覽器先生談話(以及它所說的 DOM 語言的很多方言),并且 React 自愿傳遞給我們,免費(fèi)的!
10 每一個 React 組件都有一個故事:第 2 部分
現(xiàn)在我們知道了一個組件的狀態(tài),當(dāng)該狀態(tài)發(fā)生變化的時候,我們來了解一下關(guān)于這個過程的最后幾個概念。
- 當(dāng)組件的狀態(tài)被更新時,或者它的父進(jìn)程決定更改它傳遞給組件的屬性時,組件可能需要重新渲染。
- 如果后者發(fā)生,React 會調(diào)用另一個生命周期方法:
componentWillReceiveProps
。 - 如果狀態(tài)對象或傳遞的屬性改變了,React 有一個重要的決定要做:組件是否應(yīng)該在 DOM 中更新?這就是為什么它調(diào)用另一個重要的生命周期方法
shouldComponentUpdate
的原因 。此方法是一個實(shí)際問題,因此,如果需要自行定制或優(yōu)化渲染過程,則必須通過返回 true 或 false 來回答這個問題。 - 如果沒有自定義
shouldComponentUpdate
,React 的默認(rèn)事件在大多數(shù)情況下都能處理的很好。 - 首先,這個時候會調(diào)用另一生命周期的方法:
componentWillUpdate
。然后,React 將計算新渲染過的輸出,并將其與最后渲染的輸出進(jìn)行對比。 - 如果渲染過的輸出和之前的相同,React 不進(jìn)行處理(不需要和瀏覽器先生對話)。
- 如果有不同的地方,React 將不同傳達(dá)給瀏覽器,像我們之前看到的那樣。
- 在任何情況下,一旦一個更新程序發(fā)生了,無論以何種方式(即使有相同的輸出),React 會調(diào)用最后的生命周期方法:
componentDidUpdate
。
生命周期方法是逃生艙口。如果你沒有做什么特別的事情,你可以在沒有它們的情況下創(chuàng)建完整的應(yīng)用程序。它們非常方便地分析應(yīng)用程序中正在發(fā)生的事情,并進(jìn)一步優(yōu)化 React 更新的性能。
信不信由你,通過上面所學(xué)的知識(或部分知識),你可以開始創(chuàng)建一些有趣的 React 應(yīng)用程序。如果你渴望更多,看看我的 Pluralsight 的 React.js 入門課程。
感謝閱讀。如果您覺得這篇文章有幫助,請點(diǎn)擊原文中的 ??。請關(guān)注我的更多關(guān)于 React.js 和 JavaScript 的文章。
我 Pluralsight 和 Lynda 創(chuàng)建了在線課程。我最新的文章在Advanced React.js、 Advanced Node.js 和 Learning Full-stack JavaScript中。我也做小組的在線和現(xiàn)場培訓(xùn),覆蓋初級到高級的 JavaScript、 Node.js、 React.js、GraphQL。如果你需要一個導(dǎo)師,請來找我 。如果你對此篇文章或者我寫的其他任何文章有疑問,通過這個聯(lián)系我,并且在 #questions 中提問。
感謝很多檢驗和改進(jìn)這篇文章的讀者,?ukasz Szewczak、Tim Broyles、 Kyle Holden、 Robert Axelse、 Bruce Lane、Irvin Waldman 和 Amie Wilt.
特別要感謝“驚人的” Amie,經(jīng)驗是一個實(shí)際的 Unicorn。謝謝你所有的幫助,Anime,真的非常感謝你。
掘金翻譯計劃 是一個翻譯優(yōu)質(zhì)互聯(lián)網(wǎng)技術(shù)文章的社區(qū),文章來源為 掘金 上的英文分享文章。內(nèi)容覆蓋 Android、iOS、React、前端、后端、產(chǎn)品、設(shè)計 等領(lǐng)域,想要查看更多優(yōu)質(zhì)譯文請持續(xù)關(guān)注 掘金翻譯計劃、官方微博、知乎專欄。