npx create-react-app myTest
创建完成后,项目下面主要有public
和src
文件,前者是用来存放静态资源文件的,其中最主要的就是index.html
文件,后者则是用来存放所有的react代码的
项目搭建好后,切换进项目,执行npm start
命令,即可在本地localhost:3000
窗口打开项目
运行完成后,我们可以页面看见效果
打开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
文件,来设计一个表格组件,并将这个组件添加到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>
)
}
}
保存查看页面,发现页面并没有什么变化,是一样的
所以所有组件都是可以相互嵌套的,而且简单组件和复杂组件也是可以相互嵌套的,并没有的区别
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} />
弄好之后,保存查看页面结果
通过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]
})
}
原文:https://www.cnblogs.com/zjh-study/p/10937847.html