React中的函数式和类式组件

注:学习此篇内容一定要先把类的基本知识搞懂,可参考我另一篇文章: 三分钟让你搞懂Class类 - 掘金 (juejin.cn)

本文是对网站免费资源的知识总结,如侵联删。

函数式组件

类式组件的定义

废话不多说,直接上例子:

js 复制代码
<!-- 准备好一个"容器" -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>
//1.创建类式组件
	<script type="text/babel">
		class MyComponent extends React.Component {
			render(){
				//render是放在哪里的?------ MyComponent的原型对象上,供实例使用。
				//render中的this是谁?------ MyComponent的实例对象 <=> MyComponent组件实例对象。
				console.log('render中的this:',this);
				return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<MyComponent/>,document.getElementById('test'))
         </script>
  1. 如果你了解Class的相关知识,你就能知道render其实就是MyComponent实例原型对象上的一个方法而已,那么this自然就执行MyComponent组件实例对象
  2. 渲染组件时,React做了什么:
  • React解析组件标签,找到了MyComponent组件。
  • 发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
  • 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。

组件实例三大核心属性之一:state状态

如果你的组件是有状态(state)的,就是复杂组件,反之,就是简单组件

state就是数据,不管是Vue还是React,都是靠数据驱动视图,只不过底层使用了响应式原理和自动更新视图

因为函数式组件是没有this的,因为函数式组件中采用了严格模式,而严格模式下没有this,就别谈组件实例,更别谈组件实例的核心属性了

只有类式组件有,但是后来react增加了hooks,函数式组件也有了状态

state中的this问题(重要)

那么state在哪里呢?其实React已经给我们封装好了,我们在render中打印this会发现在组件的实例对象中有context、props、refs、state等初始值 如果我们需要对类的实例化对象进行一些初始化操作,如增加一个属性,修改一个属性的值,需要借助类的构造器 写 this.xxx=xxx即可

案例:页面展示天气炎热或凉爽的文字,当点击文字时,改变文字内容

js 复制代码
<body>
	<!-- 准备好一个"容器" -->
	<div id="test"></div>
	
	<!-- 引入react核心库 -->
	<script type="text/javascript" src="../js/react.development.js"></script>
	<!-- 引入react-dom,用于支持react操作DOM -->
	<script type="text/javascript" src="../js/react-dom.development.js"></script>
	<!-- 引入babel,用于将jsx转为js -->
	<script type="text/javascript" src="../js/babel.min.js"></script>

	<script type="text/babel">
		//1.创建组件
		class Weather extends React.Component{
			
			//构造器调用几次? ------------ 1次
			constructor(props){
				super(props)
				//初始化状态
				this.state = {isHot:false,wind:'微风'}
						}

		render(){
				//读取状态
				const {isHot,wind} = this.state
				return <h1>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<Weather/>,document.getElementById('test'))
				
	</script>
</body>

到这里,都没什么难度,接下来我们要给这段文字添加一个点击事件,当点击文字的时候,文字发生改变,在做该操作之前,我们先来解决React中的小问题

小细节

我们把代码撰写如下:给文字加一个click事件,按理说这样没问题,但是我们看效果

js 复制代码
<body>
		<script type="text/babel">
		//1.创建组件
		class Weather extends React.Component{
			constructor(props){
				super(props)
				this.state = {isHot:false,wind:'微风'}
						}

		render(){
				const {isHot,wind} = this.state
				return <h1  onClick={demo()}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
			}
		}
		//2.渲染组件到页面
		ReactDOM.render(<Weather/>,document.getElementById('test'))
		function demo(){
					console.log('我被点击了');
				}		
	</script>
</body>

这说明你不是把demo函数赋给了点击事件,而是把demo函数运行完的返回值赋给了点击事件,由于demo函数中没有return 任何东西,因此就是undefined,因此不生效,此处小细节需要注意下。 我们只需要这样写,就可以了:

js 复制代码
	return <h1  onClick={demo}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>

添加点击事件

this的指向问题

我们加一个changeWeather事件,如下所示:

js 复制代码
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
	constructor(props){
	super(props)
		this.state = {isHot:false,wind:'微风'}
	}

render(){
	const {isHot,wind} = this.state
	return <h1  onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
	}
        changeWeather(){
         console.log(this.state.isHot)
        }
	}
//2.渲染组件到页面
	ReactDOM.render(<Weather/>,document.getElementById('test'))
	</script>

而当我们这样写完代码,发现竟然报错了,这里说明this是undefined,这是为何呢?

我们在changeWeather中打印this,发现真的是undefined,因为这个changeWeather不是通过组件实例调用的

解决方案1:

其实加一行代码就能解决,我们这么加

解决方案2:

基于解决方案1,我们可得到最终的解决方案2

因此最后精简之后的代码为:

js 复制代码
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
//初始化状态
state = {isHot:false,wind:'微风'}
render(){
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//自定义方法------------要用赋值语句的形式+箭头函数
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot}) 
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))			
</script>

state中setState

在上面的案例中,我们不能直接修改isHot的数据,比如:this.state.isHot=!this.state.isHot,这样写了之后,数据虽然发生了变化,但是视图并没有更新,这是因为没有触发React的响应式原理,因此要借助setState来写,即:this.setState({isHot:!isHot})

state总结

核心

  1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)

  2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)

难点

  1. 组件中render方法中的this为组件实例对象

  2. 组件自定义的方法中this为undefined,如何解决?

a) 强制绑定this: 通过函数对象的bind()

b) 箭头函数

  1. 状态数据,不能直接修改或更新
相关推荐
腾讯TNTWeb前端团队5 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom10 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom10 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom10 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试