参考文献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] }) }