这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战
上一篇文章写了React的JSX写法,也清楚了JSX是怎样的一回事、React.createElement和React Element是怎样的一个关系,今天来了解一下React的组件
一、组件的定义
在上一篇文章里有讲到React项目的目录结构,为了更简单地开始学习React项目,我仅在src目录内保留React的入口文件index.js,剩下的东西从头开始写
从Hello React开始
-
在
src目录下创建Hello.js,注意:文件有个命名规则,首字母必须为大写 -
打开
Hello.js,使用JSX进行编写并导出,使用JSX必须先导入react
import React from 'react';
//定义组件,继承 React.Component
class Hello extends React.Component {
//构造函数
constructor(props){
super(props);
this.state = {};
}
//render函数,内部编写并返回JSX模板
render() {
return (
<h1>Hello React</h1>
)
}
}
//导出组件对象
export default Hello
到这里,一个简单的Hello组件就写好了,基本流程如下:
graph TD
引入react库 --> 定义组件类并继承React.Component --> 构造函数初始化数据 --> render函数返回JSX模板 --> 利用export导出
二、组件的引用
写完了Hello组件,接下来当然就是要使用它啦!
题外话:对于真实DOM的渲染,需要引用两个库,一个是react用于JSX的编写,另一个则是react-dom用于虚拟DOM与真实DOM之间的变化(利用render方法,有ReactElement、Container、[callback]三个参数,具体可看上一篇文章)
在这里我们将Hello组件挂载到public/index.html中ID为root的元素下:
在 index.js 中使用 Hello
import React from 'react';
import ReactDOM from 'react-dom';
import Hello from './Hello';
//进行渲染
ReactDOM.render(
<Hello />,
document.getElementById('root')
)
运行后我们访问localhost:3000,可以看到Hello组件已经被成功使用
三、组件内的方法与表达式
在组件内使用变量、相应的方法是必不可少的,这里通过一个列表的例子来进行说明。
JSX中的表达式
在JSX内使用表达式,只需要用花括号{}括住即可(如{true?"one":"zero"})
组件的状态State
组件的状态是可变的,可以通过State对组件的状态更改进行改变与呈现,可通过this.setState({key:value})对状态进行更改,且这一操作并非是覆盖更改,而是定向更改(即仅对参数对象中的对象内容进行定向修改)
组件的props
props总是单项地由父组件流向子组件,props是只读的、纯净不可变的,可通过父组件修改props来触发子组件更新
State与props区别
| 条件 | State | Props |
|---|---|---|
| 从父组件中接收初始值 | True | True |
| 父组件可以改变值 | False | True |
| 在组件中设置默认值 | True | True |
| 在组件的内部变化 | True | False |
| 设置子组件的初始值 | True | True |
| 在子组件的内部更改 | False | True |
内嵌表达式的JSX以及组件内数据与方法
- 组件的创建与初始化:创建
List组件,并定义初始化状态数据,通过内嵌表达式的JSX语法进行组件编写
import React from 'react';
class List extends React.Component {
constructor(props){
super(props);
//初始化状态
this.state = {
techList:["Javascript","PHP","Java"]
};
}
render() {
return (
<ul id="list">
{
this.state.techList.map((item,index)=>{
return <li key={index+item} >{index}----{item}</li>
})
}
</ul>
)
}
}
export default List
-
组件状态的修改:通过
this.setState修改状态,通过自定义方法添加内容到列表中 -
父子组件的传参
对上方的List组件做个拆分,写一个名为ListItem的子组件,子组件同样有有key、index、item三个参数
另外,props只能是由父组件到子组件的单项数据流,且不能被子组件修改(只读),子组件可通过父组件传入的方法去修改父组件的状态
//List.js
render() {
return (
<ul id="list">
{
this.state.techList.map((item,index)=>{
return <ListItem key={index + item} item={item} index={index} />
})
}
</ul>
)
}
//ListItem.js
render() {
return (
<li>{this.props.index}----{this.props.item}</li>
)
}
- 点击事件以及列表项的删除方法
这一块我们会了解到如何定义组件的事件、子组件通过props对父组件进行状态的修改。我们先在List.js上做文章,写好删除的方法并做好事件的绑定
这里提出一个网上看到的推荐:建议将方法写在父组件上传入子组件,通过子组件去改变父组件的状态
//List.js
render() {
return (
<ul id="list">
{
this.state.map((item,index)=>{
return <ListItem deleteItem={this.deleteItem.bind(this,index)} key={index+item} index={index} item={item} />
})
}
</ul>
)
}
deleteItem(index) {
let list = this.state.techList;
list.splice(index,1);
this.setState({
techList:list
})
}
//ListItem.js
<li onClick={this.props.deleteItem} >{this.props.index}----{this.props.item}</li>
另外提一句:在绑定事件时,是需要对方法与当前this进行一次绑定的,否则this会是undefined