以下是一个简单的React组件定义和使用的示例:
import React from 'react';
// 定义一个简单的组件
class MyComponent extends React.Component {
render() {
return (
<div>
<h1>Hello, World!</h1>
<p>This is my React component.</p>
</div>
);
}
}
// 在应用中使用组件
function App() {
return (
<div>
<h2>Welcome to my app</h2>
<MyComponent />
</div>
);
}
export default App;
在上面的代码中,我们首先导入React库。然后,我们定义了一个名为MyComponent
的组件,它继承自React.Component
类。在render
方法中,我们返回了要在组件中渲染的内容。
接下来,在App
组件中,我们将MyComponent
作为一个自定义的标签使用,就像使用HTML标签一样。这样,MyComponent
就会在App
组件中被渲染出来。
最后,我们通过export default
语句将App
组件导出,以便可以在其他地方使用它。
请注意,上述代码是一个简单的示例,帮助你理解React组件的定义和使用。在实际的项目中,可能会涉及更复杂的组件结构、状态管理等。
一、组件定义
react中组件分为两种 类组件 函数组件(hooks组件)
1、类组件
/**
* 使用es module 语法引入react
* 由于我们整个项目是基于create-react-app构建
* 项目脚手架中内置了Babel等相关的语法解析工具
* 所以我们可以使用es6+相关语法进行编写
* 注意:
* 在编写react的时候尽量使用es6+语法
*/
import React from "react";
/**
* 首先导出一个类,这个类名必须全局唯一
* 并且这个类会继承React.Component 这个类(抽象类)
* 所有的类组件必须要使用class语法编写,并且必须要继承React.Component
* 注意:
* class 中使用extends 关键字实现继承,并且 该class组件拥有class
* 类所有相关的特性
*/
export default class LearnReact extends React.Component {
/**
* render函数负责渲染页面,也就是编写html(jsx)的地方
* render 函数中必须要有return,return里面只能编写html(jsx)相关代码
* 并且只能有一个根元素
* render函数每次组件重新渲染都会被调用(不然怎么渲染页面呢😄)
* 所有的react组件必须要有render函数
*/
render () {
return (
// 这里我们可以编写任意的html代码
<div>
<div>哈喽,react</div>
</div>
)
}
}
2、函数组件
/**
* 导出一个方法,方法名全局唯一
*/
export default function LearnFC () {
/**
* 如果想让改函数变成一个函数组件
* 那么就可以直接在函数里面return
* html(jsx)
* 注意:该return的html也只能有一个根节点
*/
return (
<div>
<div>哈喽,我是react中的函数组件</div>
</div>
)
}
二、使用组件
1、定义根组件
index.js文件,也就是入口文件
import React from "react";
import ReactDOM from "react-dom/client";
/**
* 使用对应的引入方式 引入组件
*/
import LearnClassComponent from "./learn-class-component";
const root = ReactDOM.createRoot(document.getElementById("root"));
/**
* 在root.render方法里面
* 防御<引入的组件>就可以定义我们的根组件
* 也就是说react中的组件创建完后,就可以使用标签语法来进行使用
*
* 那么什么是根组件呢?
* 进入项目首先展示的组件就是根组件,后期我们会在根组件上进行 创建路由等相关的扩展
*/
root.render(<LearnClassComponent />);
2、组件中使用组件
在learn-class-component文件中使用learn-fc组件
/**
* 使用es module 语法引入react
* 由于我们整个项目是基于create-react-app构建
* 项目脚手架中内置了Babel等相关的语法解析工具
* 所以我们可以使用es6+相关语法进行编写
* 注意:
* 在编写react的时候尽量使用es6+语法
*/
import React from "react";
// 引入LearnFC组件
import LearnFC from "./learn-fc";
/**
* 首先导出一个类,这个类名必须全局唯一
* 并且这个类会继承React.Component 这个类(抽象类)
* 所有的类组件必须要使用class语法编写,并且必须要继承React.Component
* 注意:
* class 中使用extends 关键字实现继承,并且 该class组件拥有class
* 类所有相关的特性
*/
export default class LearnClassComponent extends React.Component {
/**
* render函数负责渲染页面,也就是编写html(jsx)的地方
* render 函数中必须要有return,return里面只能编写html(jsx)相关代码
* 并且只能有一个根节点
* render函数每次组件重新渲染都会被调用(不然怎么渲染页面呢😄)
* 所有的react组件必须要有render函数
*/
render () {
return (
// 这里我们可以编写任意的html代码
<div>
<div>哈喽,react</div>
{/*
react会自动创建一个标签
我们可以直接使用这个标签当做组件
并且我们可以多次使用它
*/}
<LearnFC></LearnFC>
<LearnFC></LearnFC>
</div>
)
}
}
三、类组件和函数组件的区别(面试常考)
本部分内容可能牵扯到一些未讲的内容,推荐大家学完hooks之后,在回过头来回顾
简单理解
1、类组件有生命周期,函数组件没有
2、类组件需要继承 Class,函数组件不需要
3、类组件可以获取实例化的 this,并且基于 this 做各种操作,函数组件不行
4、类组件内部可以定义并维护 state, 函数组件都称为无状态了,那肯定不行。
进阶理解
函数式组件捕获了渲染时所使用的值,这是两类组件最大的不同
创建组件LearnComponentDiff
import React from "react";
import FCComponent from "./fc-component";
import ClassComponent from "./class-component";
export default class LearnComponentDiff extends React.Component {
state = {
user: "王凯",
};
render() {
return (
<>
<label>
<b>选择一个人查看关注: </b>
<select
value={this.state.user}
onChange={(e) => this.setState({ user: e.target.value })}
>
<option value="wangkai">王凯</option>
<option value="zhangsan">张三</option>
<option value="lisi">李四</option>
</select>
</label>
<h1>欢迎关注 {this.state.user}!</h1>
<p>
<FCComponent user={this.state.user} />
<b> (函数组件)</b>
</p>
<p>
<ClassComponent user={this.state.user} />
<b> (类组件)</b>
</p>
<p>你能看出两者的不同吗</p>
</>
);
}
}
创建ClassComponent类组件
import React from 'react';
class ClassComponent extends React.Component {
showMessage = () => {
alert('选择的 ' + this.props.user);
}
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return <button onClick={this.handleClick}>尝试</button>;
}
}
export default ClassComponent;
点击页面后我们发现 初始化的props改变了! user 是通过 props 下发的,props不可改变,那么造成数据改变的原因就一定是 this 指向改变了。
真正的原因也确实如此,虽然props不可改变,但是this是可变的,this.props 的每次调用都会去获取最新的 this 值,这也是React保证数据实时性的重要手段。
那么就很清晰了,当showMessage最终执行时,此时的 this 绑定的是 张三对应的上下文,所以输出为 ‘已关注 张三’
创建FCComponent函数组件
import React from 'react';
function FCComponent(props) {
const showMessage = () => {
alert('已关注 ' + props.user);
}
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
<button onClick={handleClick}>尝试</button>
);
}
export default FCComponent;
最终的输出值明显为 ‘选择的 王凯’,props 会在函数执行的瞬间就被捕获,而 props 本身又是不可变值,所以我们可以确保从当前开始读取到的 props 都是最初捕获到的。当父组件传入新的 props 尝试重新渲染函数时,本质是基于新的 props 入参重新调用了一次函数,并不会影响上一次调用。这就是 Dan 所说的函数式组件捕获了渲染所使用的值,并且我们还能进一步意识到:函数组件真正将数据和渲染紧紧的绑定到一起了
注意:
很多人认为在函数组件中延迟输出的 state 是调用时的 state,而不是最新的 state 是一个Bug,恰恰相反,这是一个函数式组件的特性,是真正践行了React设计理念的正确方式。
当然Hooks也给出了获取最新的props和state的方法,就是 useRef,详细用法在我们的课程已经有所介绍,同学们可以自行回顾一下
推荐阅读
大家可以看一下React 团队核心成员和 Redux 作者 Dan的这边文章。进阶理解这部分也借鉴了Dan大佬的这篇文章😄
https://overreacted.io/zh-hans/how-are-function-components-different-from-classes/