目录
1 创建组件
1.1 用函数创建组件
1.2 使用类创建组件
2 项目上组件的使用方式
3 事件处理
3.1 事件绑定
3.1.1 类组件绑定事件
3.1.2 函数组件绑定事件
3.2 事件对象
4 组件状态
4.1 初始化状态
4.2 获取状态
4.3 设置状态
4.3.1 箭头函数
4.3.2 重新绑定this
5 表单处理
5.1 受控组件
5.1.1 input
5.1.2 textarea
5.1.3 select
5.1.4 checkbox
5.1.5 多表单元素优化
5.2 非受控组件
6 发表评论案例
1 创建组件
1.1 用函数创建组件
创建组件的函数名称必须以大写字母开头,小写会报错导致不能成功渲染,原因是你发现html的标签首字母都是小写的,你自定义组件用大写有个区分
创建组件的函数必须有返回值,不写不行,至少要写成 return null 才不会报错
定义的时候把jsx写在return中,用的使用使用以函数名相同的标签就行了,我下面的是双标签,你也可以使用单标签
一般来讲我们不会使用箭头函数作为创建组件的函数,但箭头函数可以创建组件
1.2 使用类创建组件
用关键字class定义一个类 My_components 用关键字extends继承 React.Component
- 自定义组件需要以大写字母开头
- 需要有render(),render()中需要有return
2 项目上组件的使用方式
一般来讲每一个组件都会独占一个JS文件,之后会有一个文件夹放所有的组件JS文件,我们下面做个例子
首先在src中创建一个文件夹Components,然后在Components中创建一个JS文件,这个JS文件的名字就是组件的名字
之后在My_components.js中创建组件,然后导出
之后进入index.js,引用后就可以渲染了
用函数定义的组件也可以像上面一样导出,index.js代码不变
3 事件处理
3.1 事件绑定
3.1.1 类组件绑定事件
- this.something就是上面定义的something函数,如果你直接在onClick后的大括号中写console.log(1),那么在运行一开始就会被执行,且后面再点击是无效的
- React事件采用驼峰命名法,onClick是点击事件,onMouseEnter是鼠标移动到元素上触发的事件
按照上面的代码后点击了3次,发现可以成功绑定事件
3.1.2 函数组件绑定事件
打开后点了三下
3.2 事件对象
React中的事件对象叫做合成事件或合成事件对象,可以兼容所有浏览器
给事件处理函数一个形参就可以拿到事件对象
用法和原生JS的事件对象用法相似,比如可以获取 pageX.pageY,e.preventDefault()可以阻止浏览器的默认行为(比如a标签的跳转页面)
4 组件状态
用函数创建的组件叫无状态组件,用类创建的组件叫有状态组件,状态(state)就是数据,比如说组件是否被勾选了这种就叫状态。
当我们只需要展示数据的时候我们用函数组件,需要交互的时候我们用类组件
我们通过 state 获取状态,通过 setState() 设置状态,state的值是对象,其中包含多组键值对,这些键值对在默认情况下只能在组件内部使用(通过组件通讯可以给其他的组件使用)
4.1 初始化状态
我们可以这样初始化state,其中constructor(),super(),this.state的名称都是固定的,count及后面的值是自定义的
也可以这样初始化state,一般来讲会用下面这种,写起来比较方便
4.2 获取状态
可以使用this.state拿到状态,我们搞一下看看
4.3 设置状态
不能直接操作this.state.count,比如用等于号进行赋值,对列表push这些操作,直接进行这些操作会报错。想要设置状态要使用this.setState()进行修改
设置状态后会对组件的渲染结果产生影响,如果我们想改变组件的一些内容,我们只需要对state进行修改就可以了
这样写会有this的指向问题
点击按钮后会报错,报错的原因是不能读取 undefined属性的setState属性,也就是说此时在add_one()中的this是undefined
可以用下面两种方法解决this指向的问题
4.3.1 箭头函数
箭头函数自身不绑定this,如果写了this默认为箭头函数外一层的this,也就是你定义的组件
点三下发现没问题,既改变了state中的count,又更新了UI
也可以这样写,这样写的this指向的是render()的this,render()的this就是组件的this
还可以这样写,这样写就给this传进来了,this就不再是undefined了
4.3.2 重新绑定this
也可以对this进行重新绑定
重新绑定后可以正常使用了
5 表单处理
5.1 受控组件
5.1.1 input
定义一个状态的变量something,然后把原本的value交给这个变量something来管理,之后定义onChange事件,每一次输入框内容改变的时候都会将文本框中的内容赋值给变量something
- something是自定义的变量,名称自定
- 调整完上面说的后,此时input受React控制,我们称input为受控组件
5.1.2 textarea
textarea除了改了个标签名,剩下没有变化
5.1.3 select
select有一些区别
由于我们给了默认值,所以刚打开页面的时候,就会以默认值渲染
选择其他选项后点击按钮可以正常获取信息
5.1.4 checkbox
checkbox需要将value改成checked,变量定为布尔量
打开后会渲染指定的状态
也可以获取目前的状态
5.1.5 多表单元素优化
每用一个表单元素都得需要一个变量存储状态的值,再加上一个处理程序修改值,那样会有很多个处理程序,很麻烦
我们简单做个判断,如果类型是checkbox就拿checked属性,如果不是就拿value属性,然后给每一个表单元素一个name,name与state中的状态名称相同
点击按钮后可以获取当前状态
5.2 非受控组件
这种方式不常用,看别人写了能懂就行
使用ref对象,ref全称是reference,React中的ref对象是操作DOM用的
6 发表评论案例
打开是这样的
输入评论人和评论内容后点击发表可以把内容显示在下面
全部代码
class My_components extends React.Component {
state = {
username:"",
remark:"",
remark_list:[],
// remark_list:[{username:1,remark:2,remark_id:0},{username:1,remark:3,remark_id:1}],
remark_id:""
}
publish_remark = ()=>{
if (this.state.username.trim() && this.state.remark.trim()) {
this.setState({remark_id : this.state.remark_list.length},() => {
const new_remark_list = [{...this.state,remark_id:this.state.remark_id},...this.state.remark_list]
this.setState({remark_list : new_remark_list,username : "",remark : ""})
})
}
}
form_change = (e) => {
const value = e.target.type==='checkbox'?e.target.checked:e.target.value
this.setState({[e.target.name]:value})
}
load_remark = () => {
if (this.state.remark_list.length === 0) {
return <div>暂无评论,快去评论吧~</div>
}
else {
return (
<ul>
{this.state.remark_list.map(item => <li key={item.remark_id}>评论人:{item.username} 评论内容:{item.remark}</li>)}
</ul>
)
}
}
render() {
return (
<div>
<input type="value" placeholder= "请输入评论人" name='username' value={this.state.username} onChange={this.form_change}></input>
<br></br>
<textarea placeholder= "清输入评论内容" name='remark' value={this.state.remark} onChange={this.form_change}></textarea>
<br></br>
<button onClick={this.publish_remark}>发表评论</button>
{this.load_remark()}
</div>
)
}
}
ReactDOM.createRoot(document.querySelector('div')).render(<My_components></My_components>)
这里的这个地方是一个回调函数,在JS中执行顺序与书写顺序不一定一致,我需要首先定义一个id,然后再给id,所以定义id一定在给id的代码之前
由于不能对状态直接进行操作,所以我们要新搞一个变量 new_remark_list 来覆盖掉之前的 remark_list
其中三个点的意思是继承指定变量的所有内容,这三个点可以用于对象也可以用于列表,如果用于列表可以选择将之前的内容放在前面还是放在后面,我下面的图是放在后面,如果写 [...this.state.remark_list,{...this.state,remark_id:this.state.remark_id}] 就是将之前的内容放在新列表的前面
可以直接返回html标签,然后在render()中直接使用函数进行渲染