第2节——react组件定义及使用

以下是一个简单的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/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值