前言
上篇文章主要讲了JSX语法入门和无状态组件的传值,内容还是比较简单的,今天给大家带来React入门第三弹——有状态组件和事件处理。
组件的分类
==在React中,组件分为函数组件和class组件,也就是无状态组件和有状态组件。==
函数式组件(无状态组件)
直接定义函数的形式,不存在state,只会有props,它没有生命周期函数。// 函数式组件(无状态组件) function Hello() { return <h1>Hello,jianan</h1> }
class组件(有状态组件)
使用class定义、extends继承React.Component。有state进行数据的存储和管理,同时还可以拥有props,有生命周期函数。// class组件(有状态组件) class Hello extends React.Component { render() { return <h1>Hello jianan</h1> } }
无状态组件和有状态组件的使用规则
- 因为数据的更改都是根据状态进行更改的,如果只是单纯的处理一些逻辑,而不需要改变数据的值就使用无状态组件。我们可以使用props进行组件间的通信和传值。
- 如果需要改变某些数据的话,或是想要存储一些数据并且想要对这些数据进行一些增删改查的话,那么就应该使用有状态组件。我们使用的是state,数据会发生变化就会触发生命周期这些函数。
无状态组件和有状态组件传值的取用
- 无状态组件
使用props传值时,使用props.属性名进行取用。 - 有状态组件
使用props传值时,使用this.props.属性名进行取用。使用state定义状态时,使用this.state.属性名进行取用。
==一般数据会通过父组件进行传递,这样就可以进行统一的数据管理,在父级进行一个集中的数据管理。以上是在没有使用redux的情况下,如果使用了redux的话,就会在redux中进行状态管理。==
有状态组件
本篇文章我们先来学习有状态组件:
有状态的组件需要使用render方法进行渲染,是生命周期里面非常基础和底层的方法,一定要用它来进行渲染
<script type="text/babel">
class Hello extends React.Component {// 有状态的组件需要使用render方法进行渲染,是生命周期里面非常基础和底层的方法,一定要用它来进行渲染
render() {
return <h1>hello weiyu</h1>
}
}
ReactDOM.render(
<Hello/>,
document.getElementById("root")
)
</script>
有状态组件props传值
需要传什么值直接写在组件的上面,渲染的时候直接使用单花括号 { this.props.name }
<div id="root"></div>
<script type="text/babel">
class Hello extends React.Component {
render() {
return <div>
<h1>这是一个有状态组件</h1>
<h1>姓名:{this.props.name}</h1>
<h1>年龄:{this.props.age}</h1>
<h1>性别:{this.props.sex}</h1>
</div>
}
}
ReactDOM.render(
<Hello name="weiwei" age="18" sex="男"/>,
document.getElementById("root")
)
</script>
有状态组件state
有状态组件中state在实际开发中通常采用以下写法:
<div id="root"></div>
<script type="text/babel">
class Hello extends React.Component {
state = {
age: '16',
sex: '男'
}
render() {
return <div>
<h1>这是一个有状态组件</h1>
<h1>姓名:{this.props.name}</h1>
<h1>年龄:{this.state.age}</h1>
<h1>性别:{this.state.sex}</h1>
</div>
}
}
ReactDOM.render(
<Hello name="weiwei"/>,
document.getElementById("root")
)
</script>
==怎么选择使用有状态组件还是无状态组件?我们开发中更多的应该去使用哪种组件?==
答:更多时间尽可能的去选择使用无状态组件,因为如果是有状态组件,它就会触发生命周期所对应的一些函数。状态改变,就会触发虚拟dom重新渲染,它就会影响当前项目的运行,除非是需要对数据做一些存储、处理等,这个时候就选择有状态组件。
事件处理
事件处理函数的相关语法
React元素的事件处理和DOM元素很相似,但是语法上有些不同,React事件的命名采用小驼峰(camelCase),而不是纯小写。使用JSX语法时需要传入一个函数作为事件处理函数,而不是一个字符串。
<button onclick='fn()'>点击事件</button>
// React里
<button onClick={fn}>点击事件</button>
==另外在React中阻止默认事件不能通过返回false的形式,而是要使用preventDefault==
<a href="#" onclick="console.log('hello');return false">click</a>
handleClick(e) {
e.preventDefault()
console.log('hello')
}
<a href="#" onClick={handleClick}>click</a>
事件处理函数中的this
在JS中,class方法默认不会绑定this,如果我们忘记绑定this.handleClick并且把它传入了onClick,当我们调用这个函数的时候this的值为undefined。
class Hello extends React.Component {
constructor() {
super()
// 如果不在constructor绑定this打印出来的值是undefined
this.updateInfo = this.updateInfo.bind(this)
}
updateInfo() {
console.log(this)
}
updateState() {
console.log(this)
}
updateAge() {
console.log(this)
}
render() {
return <div>
<button onClick={this.updateInfo}>更新信息</button>
{/* 像下面这样进行绑定也是可行的 */}
<button onClick={this.updateState.bind(this)}>更新状态</button>
<button onClick={() => this.updateAge()}>更新年龄</button>
</div>
}
}
==或者使用下面这种用箭头函数赋值的方式来定义函数,这是在工作中最为常用的方法:==
class Hello extends React.Component {
updateInfo = () => {
console.log(this)
}
render() {
return <button onClick={this.updateInfo}>更新信息</button>
}
}
下面给一个完整的例子,大家可以参考:
1.点击按钮可以进行年龄的更新 2.点击第二个按钮进行 true 和 false 的切换
<script type="text/babel">
class Hello extends React.Component {
state = {
name: 'beiyu',
age: 14,
flag: true
}
updateInfo() {
console.log(this)
this.setState({
age: 5
})
}
updateState() {
this.setState({
flag: !this.state.flag
})
}
render() {
return <div>
<h1>这是一个有状态组件</h1>
<h1>姓名:{this.state.name}</h1>
<h1>年龄:{this.state.age}</h1>
<button onClick={this.updateInfo.bind(this)}>更新年龄</button>
<button onClick={() => this.updateState()}>{this.state.flag ? 'TRUE' : 'FALSE' }</button>
</div>
}
}
ReactDOM.render(
<Hello/>,
document.getElementById("root")
)
</script>
事件处理&条件处理
我们通过例子来学习:根据登录状态来展示不同的组件,true展示login组件,false展示logout组件
<script type="text/babel">
function Login() {
return <button>login</button>
}
function Logout() {
return <button>logout</button>
}
class Hello extends React.Component {
state = {
isLogin: true
}
updateState = () => {
this.setState({
isLogin: !this.state.isLogin
})
}
render() {
// const isLogin = this.state.isLogin
const { isLogin } = this.state
return <div>
<h1>这是一个有状态组件</h1>
{ isLogin ? <Login/> : <Logout/> }
<button onClick={this.updateState}>更新状态</button>
</div>
}
}
ReactDOM.render(
<Hello/>,
document.getElementById("root")
)
</script>
==React中为什么要使用setState修改状态?==
答:React没有实现类似于Vue2的Object.defineProperty或者是Vue3的proxy方式来监听数据的变化,所以必须通过setState来告知react状态的改变,setState是继承自Component,当我们调用setState的时候会重新执行render方法
受限组件
Vue事项了响应式数据,但是React中不具备响应式特性,所以在应用中有很多东西需要我们手动完成
<script type="text/babel">
class Hello extends React.Component {
render() {
return <input type="text" value="123" />
}
}
ReactDOM.render(
<Hello/>,
document.getElementById("root")
)
</script>
此时Hello作为一个受限组件渲染出来之后,我们去输入输入框任何值都无效,如果要响应用户输入的值,就必须使用onChange事件。
下面我们来进行改写,并且实现数据的双向绑定
<div id="root2"></div>
<script type="text/babel">
class App extends React.Component {
state = {
value: 'hello'
}
change = (event) => {
console.log(event);
this.setState({
value: event.target.value
})
}
render() {
return <div>
<input type="text" value={this.state.value} onChange={this.change} />
<h2>{this.state.value}</h2>
</div>
}
}
ReactDOM.render(
<App/>,
document.getElementById("root2")
)
</script>
给input绑定onChange事件,然后在change函数中给value赋值event.target.value
==这里我们在函数中传入了event参数,打印出来就可以看见event.target.value就是我input中输入的值==
双向绑定效果:
最后
本期给大家介绍了有状态组件以及事件处理,关于本篇中的案例,大家可以自己动手操作实现以下,后面会继续给大家介绍使用react实现表单的一些操作~
欢迎关注,持续更新!!>>>>>