一、創建項目
npx create-react-app myTest
創建完成后,項目下面主要有public
和src
文件,前者是用來存放靜態資源文件的,其中最主要的就是index.html
文件,后者則是用來存放所有的react代碼的
項目搭建好后,切換進項目,執行npm start
命令,即可在本地localhost:3000
窗口打開項目
二、修改app.js
運行完成后,我們可以頁面看見效果
打開src文件夾,里面有個index.js和app.js文件,其中index.js是主入口文件,app.js就是頁面展示建議react組件,現在修改一下app.js里面的東西,寫入Hello React !
,然后保存看看頁面
書寫代碼有jsx和非jsx語法兩種格式:
jsx
const h1 = <h1 class="app-title">Hello React !</h1>
no-jsx
const h1 = React.createElement('h1', {className: 'app-title'}, 'Hello React !')
三、創建Table.js
現在新建一個table.js
文件,來設計一個表格組件,並將這個組件添加到app.js
組件中
新建組件注意事項
1、Component
作為一個組件引入了,不需要再執行React.Component
2、使用class繼承,元素必須在render()
方法里面返回
3、樣式類名書寫是className,不是class
4、一定要將組件導出export default componentName
5、react組件名必須大寫字母開頭
6、只能return一個根元素,不能return兩個根元素,也就是說renturn的標簽必須包裹在一個根標簽里面,不能是兩個同級標簽
import React, { Component } from 'react'
class Table extends Component {
render() {
return (
<table>
<thead>
<tr>
<td>Name</td>
<td>Job</td>
</tr>
</thead>
<tbody>
<tr>
<td>李狗蛋</td>
<td>程序猿</td>
</tr>
<tr>
<td>王翠花</td>
<td>攻城獅</td>
</tr>
</tbody>
</table>
)
}
}
export default Table
組件寫好后,在app.js里面引入組件並使用
import Table from './table.js'
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<h4>Hello React !</h4>
<Table />
</header>
</div>
);
}
然后保存查看頁面
看起來樣子有些丑,然后創建一個table.css文件,書寫一些樣式,讓table美觀一下,然后在table.js頁面引入css文件
import './table.css'
然后保存查看頁面
四、簡單組件
其實通過class創建的組件可以稱之為復雜組件,還可以創建簡單組件,所謂的簡單組件,其實用類似函數的方式聲明組件,現在用簡單組件把table的頭部和軀體部分分別分離出來作為一個單獨的小組件
簡單組件跟復雜組件的區別之一就是簡單組件不需要render()方法去置換一下return元素,直接返回react元素
// table.js
function TableHead(props) {
return (
<thead>
<tr>
<th>Name</th>
<th>Job</th>
</tr>
</thead>
)
}
function TableBody(props) {
return (
<tbody>
<tr>
<td>李狗蛋</td>
<td>程序猿</td>
</tr>
<tr>
<td>王翠花</td>
<td>攻城獅</td>
</tr>
</tbody>
)
}
調用
class Table extends Component {
render() {
return (
<table>
<TableHead />
<TableBody />
</table>
)
}
}
保存查看頁面,發現頁面並沒有什么變化,是一樣的
所以所有組件都是可以相互嵌套的,而且簡單組件和復雜組件也是可以相互嵌套的,並沒有的區別
五、組件通信props
react中組件通信跟vue有點類似,是通過props來接收數據傳遞,不同的是:
1、數據是全局保存在props對象里面的,直接調用props對象就可以獲取
2、數據傳遞也不需要通過v-bind
來綁定參數,直接寫即可,只不過傳入參數使用{}
包裹,而不是""
3、在簡單函數里,props是作為一個參數傳入的,所以直接通過props.key獲取,但是在class里面,props是繼承於Compoent,需要通過super()
方法,調用是通過this.props.key
因為所有組件都是在app.js里面渲染的,所以現在要在app.js里面創建數據傳遞過去,需要注意一點就是傳遞的數據必須創建在渲染組件元素的render()
函數里面,創建在render()
方法之外,是沒有效果的,如果是簡單組件,就直接聲明一個數據數組
數據聲明好之后,直接在組件上傳遞
function App() {
const Head = [
{ header: 'Name' },
{header: 'Job'}
]
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<h4>Hello React !</h4>
// 傳遞數據
<Table Head={Head} />
</header>
</div>
);
}
接下來就可以在Table組件的render函數通過es6方法從props里面拿到數據賦值給新聲明的變量,注意必須在render()方法里面聲明獲取,簡單函數直接聲明獲取獲取
class Table extends Component {
render() {
// 拿取元素
const {Head} = this.props
return (
<table>
<TableHead Head={Head} />
<TableBody />
</table>
)
}
}
接下里就是列表渲染表格頭部了,注意react里面列表渲染時通過map()
方法實現的,因為map()方法返回的是一個結果數組
需要注意的是每一個循環創建的react元素必須賦予一個key
值,這是唯一標識符,同一個react元素里不能相同
const TableHead = (props) => {
const myHead = props.Head.map((item, index) => {
return <th key={index}>{item.header}</th>
})
return (
<thead>
<tr>
{myHead}
</tr>
</thead>
)
}
然后保存查看頁面,發現頁面結構數據並沒有變化,也沒有報錯
同理我們可以把body數據也可以賦予過去
const Body = [
{
name: '李狗蛋',
job: '程序猿',
},
{
name: '王翠花',
job: '攻城獅',
},
{
name: '二狗子',
job: '加班狗',
}
]
<Table Head={Head} Body={Body} />
弄好之后,保存查看頁面結果
六、數據修改state
通過props可以傳遞數據,但是這個數據傳過去后是不可變的,無法進行操作,所以需要通過state來聲明數據,這樣數據就可以通過this.setState()
方法來進行相關操作
現在我們創建一個state對象,把先前的數據全部移到這個對象里面
const state = {
Head: [
{ header: 'Name' },
{header: 'Job'}
],
Body: [
{
name: '李狗蛋',
job: '程序猿',
},
{
name: '王翠花',
job: '攻城獅',
},
{
name: '二狗子',
job: '加班狗',
}
]
}
在Table組件依然是通過this.props獲取這個數據
現在我們需要操作這個數組,來進行數組的內容的添加和刪除,首先我們執行刪除操作,在app.js聲明一個刪除數據的方法,用來執行刪除,這個方法是根據index來刪除
刪除函數
removeTr = index => {
const { Body } = this.state
this.setState({
Body: Body.filter((item, ind) => {
return ind !== index
})
})
}
弄好之后,把數據通過props傳遞過去,然后回到Table組件,在body里面新增一行,執行方法
function TableBody(props) {
const myBody = props.Body.map((item, index) => {
return <tr key={index}>
<td>{item.name}</td>
<td>{item.job}</td>
<td>
<button onClick={() => props.removeTr(index)}>Delete</button>
</td>
</tr>
})
return (
<tbody>
{myBody}
</tbody>
)
}
注意
這里踩了一個坑,通過事件執行方法時,一定要通過一個函數去執行props里傳過來的方法,否則好像會自動執行
這樣我們點擊刪除按鈕,就會將當前的數組索引作為參數傳過去,然后通過filter()
方法過濾掉index相同的數組項,返回其他數組項,實現刪除效果
七、新增數據
在做邏輯操作之前,我們需要新建一個新增數據的表單組件
Form.js
import React, { Component } from 'react'
class Form extends Component {
constructor(props) {
super(props)
// 初始化input的value值
this.initValue = {
name: '',
job: '',
}
// 將初始化值賦值給state
this.state = this.initValue
}
// input標簽內容改變時執行
handleChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
})
}
// 點擊提交按鈕時執行的操作
submitForm = () => {
// 這個方法是app.js那邊傳過來的,這個需要把用戶輸入的數據傳過去
this.props.handleSubmit(this.state)
// 重置input的value值
this.setState(this.initValue)
}
render() {
const {name, job} = this.state
return (
<form>
<label>
Name:
</label>
<input type="text" value={name} name="name" onChange={this.handleChange} /><br />
<label>
Job:
</label>
<input type="text" value={job} name="job" onChange={this.handleChange} /><br />
<input type="button" value="新增" onClick={this.submitForm} />
</form>
)
}
}
app.js
handleSubmit = (valObj) => {
// 通過解構的方式,把傳過來的數據添加到Body數組里,
this.setState({
Body: [...this.state.Body, valObj]
})
}