視訊教程
本文章在B站配有視訊教程
課程目標
- 瞭解最常用的React概念和相關術語,例如JSX,元件,屬性(Props),狀態(state)。
- 構建一個非常簡單的React應用程式,以闡述上述概念。
最終效果
建立React應用
helloworld
(1)安裝node.js 官網連結
(2)開啟cmd 視窗 輸入
npm install --g create-react-app
npm install --g yarn
(-g 代表全域性安裝)
如果安裝失敗或較慢。需要換源,可以使用淘寶NPM映象,設定方法為:
npm config set registry https://registry.npm.taobao.org
,設定完成後,
重新執行
cnpm install --g create-react-app
cnpm install --g yarn
安裝 creat-react-app 功能元件,該元件可以用來初始化一個專案, 即 按照一定的目錄結構,生成一個新專案
(3)在你想建立專案的目錄下 例如 D:/project/ 開啟cmd命令 輸入
create-react-app react-tutorial
去使用creat-react-app命令建立名字是react-tutorial的專案
安裝完成後,移至新建立的目錄並啟動專案
cd react-tutorial
yarn start
一旦執行此命令,localhost:3000新的React應用程式將彈出一個新視窗。
專案目錄結構
一個/public和/src目錄,以及node_modules,.gitignore,README.md,和package.json。
在目錄/public
中,重要檔案是index.html
,其中一行程式碼最重要
<div id="root"></div>
該div做為我們整個應用的掛載點
/src
目錄將包含我們所有的React程式碼。
要檢視環境如何自動編譯和更新您的React程式碼,請找到檔案/src/App.js
:
將其中的
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
修改為
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
和豆約翰 Learn React
</a>
儲存檔案後,您會注意到localhost:3000
編譯並重新整理了新資料。
現在刪除/src
目錄中的所有檔案,我們將從頭開始建立自己的專案檔案。
開始我們的mini專案
1.新建檔案index.css
我們就拷貝index.css檔案的全部內容(css不是我們這次課程的重點).
2.新建檔案index.js
在index.js中,我們將匯入React,ReactDOM和CSS檔案。
src / index.js
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
建立App元件,在render方法中返回一個div(這裡是JSX語法)
src / index.js
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
最後,我們將App渲染到根節點。
src / index.js
ReactDOM.render(<App />, document.getElementById('root'))
index.js完整程式碼
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import './index.css'
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'))
在瀏覽器輸入localhost:3000,您將看到“你好,React!
JSX:JavaScript + XML
如您所見,我們在React程式碼中一直使用看起來像HTML的東西,但它並不是完全HTML。這是JSX,代表JavaScript XML。
使用JSX,我們可以編寫看起來像HTML的內容,也可以建立和使用我們自己的類似XML的標籤。
以下是JSX分配給變數的樣子:
const heading = <h1 className="site-heading">Hello, React</h1>
編寫React並非必須使用JSX。在幕後,它正在執行createElement,它接受標籤,包含屬性象和元件的後代,並呈現相同的資訊。下面的程式碼將具有與上面的JSX相同的輸出。
const heading = React.createElement('h1', { className: 'site-heading' }, 'Hello, React!')
JSX實際上更接近JavaScript,而不是HTML,因此在編寫時需要注意一些關鍵區別。
- className用於代替class新增CSS類(classJavaScript中的保留關鍵字)。
- JSX中的屬性和方法為camelCase(駝峰表示法) - onclick將變為onClick。
- 自閉合標籤必須以斜槓結尾-例如
- JavaScript表示式也可以使用大括號(包括變數,函式和屬性)嵌入JSX內。
const name = 'Tania'
const heading = <h1>Hello, {name}</h1>
JSX比在原生JavaScript中建立和新增元素更容易編寫和理解,這也是人們如此熱愛React的原因之一。
元件
到目前為止,我們已經建立了一個元件- App元件。React中的幾乎所有內容都由元件組成,這些元件可以是類元件或簡單元件。
大多數React應用程式都有許多小元件,所有內容都載入到主App元件中。
元件經常定義在單個js檔案中,
接下來讓我們更改專案。從index.js中刪除App類:
index.js
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './index.css'
ReactDOM.render(<App />, document.getElementById('root'))
我們將建立一個新檔案App.js,並將元件放入其中。
import React, { Component } from 'react'
class App extends Component {
render() {
return (
<div className="App">
<h1>Hello, React!</h1>
</div>
)
}
}
export default App
我們將元件匯出為App並將其載入到中index.js。將元件分成檔案不是強制性的,但是如果不這樣做的話,應用程式將開始變得笨拙和混亂。
類元件
讓我們建立另一個元件。我們將建立一個表格。製作Table.js,並用以下資料填充。
src / Table.js
import React, { Component } from 'react'
class Table extends Component {
render() {
return (
<table>
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
<tr>
<td>Mac</td>
<td>Bouncer</td>
</tr>
<tr>
<td>Dee</td>
<td>Aspiring actress</td>
</tr>
<tr>
<td>Dennis</td>
<td>Bartender</td>
</tr>
</tbody>
</table>
)
}
}
export default Table
我們建立的該元件是一個自定義類元件。自定義元件名稱首字母大寫,以區別於常規HTML元素。回到App.js,我們可以先將表格元件匯入,以載入表格元件:
src / App.js
import Table from './Table'
然後將其載入到App類的render()函式中,在此之前我們已經有了“ Hello,React!”。還更改了外部容器的類名。
import React, { Component } from 'react'
import Table from './Table'
class App extends Component {
render() {
return (
<div className="container">
<Table />
</div>
)
}
}
export default App
現在,我們已經瞭解了什麼是自定義類元件。我們複用此元件。但是,由於資料已被硬編碼到其中,因此目前它並不太有用。
簡單元件
React中的另一種型別的元件是simple component,它是一個函式。該元件不使用class關鍵字。讓我們為Table元件製作兩個簡單的子元件-一個表頭和一個表主體。
我們將使用ES6箭頭表示式來建立這些簡單的元件。首先,表頭:
src / Table.js
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
然後是表主體。
src / Table.js
const TableBody = () => {
return (
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
<tr>
<td>Mac</td>
<td>Bouncer</td>
</tr>
<tr>
<td>Dee</td>
<td>Aspiring actress</td>
</tr>
<tr>
<td>Dennis</td>
<td>Bartender</td>
</tr>
</tbody>
)
}
現在,我們的Table.js檔案將如下所示。請注意,TableHeader和TableBody元件都在同一個檔案中,並由Table類元件使用。
src / Table.js
import React, { Component } from 'react'
const TableHeader = () => {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
const TableBody = () => {
return (
<tbody>
<tr>
<td>Charlie</td>
<td>Janitor</td>
</tr>
<tr>
<td>Mac</td>
<td>Bouncer</td>
</tr>
<tr>
<td>Dee</td>
<td>Aspiring actress</td>
</tr>
<tr>
<td>Dennis</td>
<td>Bartender</td>
</tr>
</tbody>
)
}
class Table extends Component {
render() {
return (
<table>
<TableHeader />
<TableBody />
</table>
)
}
}
export default Table
執行結果不變。如您所見,元件可以巢狀在其他元件中,並且簡單和類元件可以混合使用。
一個類元件必須包含render(),並且return只能返回一個父元素。
作為總結,讓我們比較一個簡單的元件和一個類元件:.
簡單元件
const SimpleComponent = () => {
return <div>Example</div>
}
類元件
class ClassComponent extends Component {
render() {
return <div>Example</div>
}
}
props
我們的Table元件,資料是硬編碼的。關於React的重要問題之一是它如何處理資料,它使用屬性(props)和狀態(state)來處理資料。現在,我們將專注於使用props處理資料。
首先,讓我們從TableBody元件中刪除所有資料。
src / Table.js
const TableBody = () => {
return (
<tbody></tbody>
)
}
然後,將所有資料定義到一個物件陣列中:
src / App.js
class App extends Component {
render() {
const characters = [
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]
return (
<div className="container">
<Table />
</div>
)
}
}
接下來,我們將通過屬性characterData將資料傳遞給子元件Table,傳遞的資料是characters變數,由於它是JavaScript表示式,因此使用大括號括起來。
return (
<div className="container">
<Table characterData={characters} />
</div>
)
現在資料已經傳遞到Table元件,我們可以在Table元件通過this.props中訪問到。
src / Table.js
class Table extends Component {
render() {
const { characterData } = this.props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} />
</table>
)
}
}
由於Table元件實際上由兩個較小的簡單元件組成,因此再次通過props 將其傳遞給子元件TableBody
我們將把props作為引數傳遞給簡單元件TableBody ,並通過陣列的map方法將資料對映為jsx片段的集合。該jsx片段集合將包含在rows
變數中,我們將其作為表示式返回。
const TableBody = props => {
const rows = props.characterData.map((row, index) => {
return (
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
</tr>
)
})
return <tbody>{rows}</tbody>
}
您會注意到我已經向每個錶行新增了一個鍵索引。在React中建立列表時,應始終使用鍵,因為它們有助於識別每個列表項。我們還將在需要操縱列表項的時刻看到這是必要的。
props是將現有資料傳遞到React元件的有效方法,但是該元件無法更改props-它們是隻讀的。在下一節中,我們將學習如何使用狀態(state)來進一步控制React中的資料處理。
state
我們將表格資料儲存在陣列變數中,並將其作為props傳遞。但是如果我們希望能夠從陣列中刪除一個專案,就做不到了。props,是一種單向資料流,子元件不能進行修改。但是有了state,我們就可以更新元件中的私有資料。
您可以將state視為可以在元件內增刪改的而不必新增到資料庫的任何臨時資料-例如,在確認購買之前在購物車中新增和刪除的購物車專案。state改變後,繫結state資料的檢視會自動更新。
首先,我們將建立一個state物件。
src / App.js
class App extends Component {
state = {}
}
在state物件中定義屬性,儲存我們所需的資料。
src / App.js
class App extends Component {
state = {
characters: [],
}
}
將我們之前建立的物件的整個陣列移到中state.characters。
class App extends Component {
state = {
characters : [
{
name: 'Charlie',
job: 'Janitor',
},
{
name: 'Mac',
job: 'Bouncer',
},
{
name: 'Dee',
job: 'Aspring actress',
},
{
name: 'Dennis',
job: 'Bartender',
},
]
}
}
在App.js中,建立removeCharacter方法來刪除一個專案
removeCharacter = index => {
const { characters } = this.state
this.setState({
characters: characters.filter((character, i) => {
return i !== index
}),
})
}
您必須使用this.setState()來修改陣列。簡單地將新值應用到this.state.property將不起作用。
現在,我們必須將該函式傳遞給元件。我們會將removeCharacter函式作為屬性傳遞給Table。
src/App.js
render() {
const { characters } = this.state
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
</div>
)
}
由於Table元件,並不需要自己的state資料物件,所以,我們將它改造成簡單元件,並將removeCharacter函式繼續向TableBody 子元件傳遞:
src/Table.js
const Table = props => {
const { characterData, removeCharacter } = props
return (
<table>
<TableHeader />
<TableBody characterData={characterData} removeCharacter={removeCharacter} />
</table>
)
}
在TableBody元件中,我們將鍵/索引作為引數傳遞,因為removeCharacter函式知道要刪除的專案索引。我們建立一個按鈕並將其onClick事件繫結removeCharacter函式;
src/Table.js
<tr key={index}>
<td>{row.name}</td>
<td>{row.job}</td>
<td>
<button onClick={() => props.removeCharacter(index)}>Delete</button>
</td>
</tr>
onClick事件必須繫結為返回該removeCharacter()方法的函式,否則removeCharacter()將嘗試不等按鈕點選而自動執行。
新增表格資料
現在我們已經將資料儲存在App.js元件的state物件中,並且可以從state物件中刪除任何專案。但是,如何向state物件中新增資料呢?我們將通過一個表單元件來實現這個需求。
首先,state.characters中刪除所有硬編碼資料:
src / App.js
class App extends Component {
state = {
characters: [],
}
}
建立新檔案Form.js。
import React, { Component } from 'react'
class Form extends Component {
initialState = {
name: '',
job: '',
}
state = this.initialState
}
以前,React類元件有必要包括一個constructor(),但是現在不再需要。
此表單的目標是Form每次更改表單中的欄位時都會更新本元件(Form)的state,並且在我們提交表單時,所有資料都將傳遞給App元件的state,然後Table元件會自動更新。
首先定義input控制元件的onChange事件處理函式:
src / Form.js
handleChange = event => {
const { name, value } = event.target
this.setState({
[name]: value,
})
}
Form元件的render函式實現如下:
src / Form.js
render() {
const { name, job } = this.state;
return (
<form>
<label htmlFor="name">Name</label>
<input
type="text"
name="name"
id="name"
value={name}
onChange={this.handleChange} />
<label htmlFor="job">Job</label>
<input
type="text"
name="job"
id="job"
value={job}
onChange={this.handleChange} />
</form>
);
}
export default Form;
在App.js,匯入Form:
import Form from './Form';
return (
<div className="container">
<Table characterData={characters} removeCharacter={this.removeCharacter} />
<Form />
</div>
)
最後一步是實現提交該資料並更新父元件狀態。我們將建立一個名為handleSubmit()
的函式,該函式將使用[ES6擴充套件運算子]語法來更新狀態。
src / App.js
handleSubmit = character => {
this.setState({ characters: [...this.state.characters, character] })
}
確保我們將其作為引數傳遞給Form
。
<Form handleSubmit={this.handleSubmit} />
現在,在Form
中,我們將建立一個名為submitForm()
的方法,該方法將呼叫傳進來的handleSubmit函式,並將Form
的state作為character
引數傳遞。它還將Form
的state重置為初始狀態,以在表單提交後清除表單資訊。
src / Form.js
submitForm = () => {
this.props.handleSubmit(this.state)
this.setState(this.initialState)
}
最後,我們將在Form.js中新增一個提交按鈕以提交表單,點選將呼叫我們剛定義的submitForm
函式。
src / Form.js
<input type="button" value="Submit" onClick={this.submitForm} />
就是這樣!該應用程式已完成。