參考文獻css
npx create-react-app myTest
建立完成後,項目下面主要有public
和src
文件,前者是用來存放靜態資源文件的,其中最主要的就是index.html
文件,後者則是用來存放全部的react代碼的
項目搭建好後,切換進項目,執行npm start
命令,便可在本地localhost:3000
窗口打開項目html
運行完成後,咱們能夠頁面看見效果
打開src文件夾,裏面有個index.js和app.js文件,其中index.js是主入口文件,app.js就是頁面展現建議react組件,如今修改一下app.js裏面的東西,寫入Hello React !
,而後保存看看頁面
書寫代碼有jsx和非jsx語法兩種格式:
jsxvue
const h1 = <h1 class="app-title">Hello React !</h1>
no-jsxreact
const h1 = React.createElement('h1', {className: 'app-title'}, 'Hello React !')
如今新建一個table.js
文件,來設計一個表格組件,並將這個組件添加到app.js
組件中
新建組件注意事項
一、Component
做爲一個組件引入了,不須要再執行React.Component
二、使用class繼承,元素必須在render()
方法裏面返回
三、樣式類名書寫是className,不是class
四、必定要將組件導出export default componentName
五、react組件名必須大寫字母開頭
六、只能return一個根元素,不能return兩個根元素,也就是說renturn的標籤必須包裹在一個根標籤裏面,不能是兩個同級標籤es6
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裏面引入組件並使用npm
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'
而後保存查看頁面
app
其實經過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> ) }
調用this
class Table extends Component { render() { return ( <table> <TableHead /> <TableBody /> </table> ) } }
保存查看頁面,發現頁面並無什麼變化,是同樣的
因此全部組件都是能夠相互嵌套的,並且簡單組件和複雜組件也是能夠相互嵌套的,並無的區別
react中組件通訊跟vue有點相似,是經過props來接收數據傳遞,不一樣的是:
一、數據是全局保存在props對象裏面的,直接調用props對象就能夠獲取
二、數據傳遞也不須要經過v-bind
來綁定參數,直接寫便可,只不過傳入參數使用{}
包裹,而不是""
三、在簡單函數裏,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} />
弄好以後,保存查看頁面結果
經過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] }) }