函数式组件

React的图形界面其实就是通过一层层的组件构建而成的。本篇笔记我们介绍React中组件的概念,以及组件状态和生命周期相关的概念和用法。

定义并渲染组件

在早期版本React曾经广泛使用class定义组件,但这种方式在最新的版本中已经弃用了,取而代之的是函数式组件和Hooks,本系列笔记的后续内容也将使用这种代码风格进行介绍。

下面例子代码中,我们创建了一个最简单的组件<App />并将其渲染到DOM中。

import React from "react";
import ReactDOM from "react-dom/client";

const App = () => {
  return <div>Hello, React!</div>;
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

代码中,App就是一个函数式组件,它的功能比较简单,它没接收任何参数,只是输出一些HTML内容。虽然这里App本质上是一个函数,但React要求作为组件名必须以大写字母开头,即PascalCase命名,否则可能无法正确渲染。这里还要注意的是组件返回的HTML必须是树形的,即必须存在一个根节点,如果不希望使用<div></div>包裹,也可以用空标签<>

熟悉JavaScript语言的同学可能发现上面代码的写法并不符合JavaScript标准,return的返回值居然是一段HTML代码,这其实是JSX的用法,JSX你可以将其理解为一种JavaScript的语法糖,在React中构建图形界面都是使用JSX来输出内容的。

随后,我们调用了ReactDOM.createRoot()方法,它将React组件挂载到了HTML中的真实DOM节点上,后续就会以这个节点挂载的组件为根组件进行内容的渲染,最后我们调用root.render()App组件渲染到了根节点上。

一些额外说明:

  1. 一些老的教程可能会在挂载节点时使用ReactDom.render()方法,该方法已经弃用。
  2. 代码中我们使用了React.StrictMode包裹了我们的根组件,这是新版本React提供的严格模式功能,严格模式能够进行额外的检查并输出一些警告信息,对我们开发阶段很有帮助,建议开启。
  3. 实际开发中,建议将组件抽离到单独的文件中,以使代码结构更加清晰。

组件树

React的图形界面就是通过组件一层层嵌套构成的,它是一个树形结构。引用子组件非常简单,我们直接在父组件JSX中像使用HTML标签一样引用子组件即可:

return (
  <div>
    <ChildComponent></ChildComponent>
  </div>
);

维护组件内部状态

React组件的状态数据分为两种:propsstate,这些状态数据的改变都会引发组件的重新渲染。两者的区别是:props是组件对外的数据接口,用于将数据从父组件传递给子组件;而state用于维护组件内部的状态数据。

state

state用于维护组件内部的状态数据,下面例子中,我们的组件内部维护一个数字变量,点击按钮时数字加1。

import { useState } from "react";

const App = () => {
  const [cnt, setCnt] = useState(0);

  const incrementCnt = () => {
    setCnt(cnt + 1);
  };

  return (
    <div>
      <button onClick={incrementCnt}>ClickMe</button>
      {cnt}
    </div>
  );
};

export default App;

我们这里定义了App组件,和之前不同的是这里我们使用了useState()这个Hooks函数,它用于创建组件状态。useState()的返回值比较特殊,它返回有2个元素的数组,第1个元素用于读取当前状态值,第2个元素是一个Set函数,用于设置状态值。代码中的incrementCnt()是我们自定义的函数,它用于作为按钮点击的回调函数,每次触发就会将cnt的值加1。最后,在返回的JSX中,我们关联了按钮的点击和incrementCnt()函数,并将cnt的值显示出来。

注意:

  1. 修改state值必须通过Set函数,直接修改值是不会触发组件函数重新执行的。
  2. 状态的Set函数是异步的,修改后无法直接立即获取到新的值,如果需要获取新值可以通过useEffect()对状态数据进行监听。

有关更多Hooks函数的使用我们会在后续章节用到时详细介绍。

props

props是组件对外的数据接口,用于将数据从父组件传递给子组件。下面例子中,我们将数据从ParentComponent传到ChildComponent

ParentComponent.jsx

import ChildComponent from "./ChildComponent";

const ParentComponent = () => {
  return <ChildComponent text="hello"></ChildComponent>;
};

export default ParentComponent;

ChildComponent.jsx

const ChildComponent = (props) => {
  return <div>{props.text}</div>;
};

export default ChildComponent;

代码中,我们的父组件ParentComponent引用了子组件ChildComponent,并通过props向子组件传递了参数text="hello",子组件中我们可以通过props.text进行读取。

这里要注意2个规则:

  1. 父组件改变子组件的props值时,会触发子组件的重新渲染
  2. props在子组件中是只读的,不可以改变,但你可以将props作为初始值再赋予一个state

组件的生命周期

React中,组件的生命周期主要分为3部分:

装载(mount):组件第一次在DOM树中渲染

更新(update):组件被重新渲染

卸载(unmount):组件从DOM树中删除

在老版本的ClassComponent中,React提供了许多生命周期回调函数用于处理这些生命周期,但在新版本的函数式组件中,取消了这些回调函数,但我们依然可以通过useEffect()来实现同样的功能。

import { useEffect } from "react";

const App = () => {
  useEffect(() => {
    console.log("mount & update");
  }, []);

  return <div></div>;
};

export default App;

上面代码运行时,我们可以看到组件在加载后输出相关的信息。

作者:Gacfox
版权声明:本网站为非盈利性质,文章如非特殊说明均为原创,版权遵循知识共享协议CC BY-NC-ND 4.0进行授权,转载必须署名,禁止用于商业目的或演绎修改后转载。
Copyright © 2017-2024 Gacfox All Rights Reserved.
Build with NextJS | Sitemap