3、React核心概念:JSX语法、组件化思想、函数组件与类组件、组件的挂载与渲染

好,咱们进入第三章。这一章可以说是React的「地基」。

你想想看,不管以后你用React写多复杂的项目,最终都绕不开这几个概念:JSX怎么写、组件怎么拆、函数组件和类组件选哪个、组件又是怎么跑到页面上的。

我个人习惯,每次带新人时,都会先让他们把这章吃透。因为很多坑,其实都是基础概念没搞明白埋下的。

3.1 JSX语法:为什么在JavaScript里写HTML?

我第一次看到JSX时,心里也犯嘀咕:「这什么玩意儿?HTML和JS混在一起,不乱吗?」

但用了一段时间后,我承认——真香。

JSX是什么?

JSX是JavaScript的语法扩展。它长得像HTML,但本质是JS。React用它来描述UI结构。

const element = <h1>Hello, React!</h1>;

你看,这行代码既不是纯HTML,也不是纯JS。但它能跑。因为React会通过Babel把它编译成 React.createElement() 调用。

核心要点:JSX最终会被编译成普通的JavaScript函数调用。所以JSX里可以写任何JS表达式。

JSX的规则,记住这几点就够了:

  • 只能有一个根元素——可以用 <></> 空标签包裹
  • 属性用驼峰命名——比如 classNameonClick
  • 花括号里写JS表达式——比如 {变量}{函数调用()}
  • 条件渲染用三元运算符——比如 {isLogin ? <User /> : <Guest />}

我的小技巧:写JSX时,我习惯把逻辑尽量抽到外面。JSX里只保留简单的三元判断或map循环。太复杂的逻辑放外面,代码会清爽很多。

3.2 组件化思想:把页面拆成积木

说白了,组件化就是把一个页面拆成一个个独立的小块。每个小块只管自己的事。

我在项目中遇到过最典型的反例:一个页面文件写了2000行代码,改一个按钮要滚动半天。后来重构时,我把它拆成了十几个小组件,每个组件不超过100行。维护起来舒服多了。

为什么要组件化?

  • 复用——写一次,到处用
  • 隔离——改A组件,不影响B组件
  • 可测试——每个组件可以单独测
  • 好理解——看一眼组件名,就知道它干嘛的

你想想看,一个页面就像一栋楼。组件就是砖块、门窗、水管。每个部件独立生产,最后组装起来。出了问题,换那块砖就行,不用拆楼。

3.3 函数组件 vs 类组件:我该用哪个?

这个问题,几乎每个初学者都会问。我直接说结论:现在优先用函数组件 + Hooks

但类组件你也要懂。因为很多老项目还在用,面试也常考。

函数组件长这样:

function Welcome(props) {
  return <h1>你好,{props.name}</h1>;
}

简单、直接。就是一个接收props、返回JSX的函数。

类组件长这样:

class Welcome extends React.Component {
  render() {
    return <h1>你好,{this.props.name}</h1>;
  }
}

类组件必须继承 React.Component,而且必须实现 render() 方法。

对比项 函数组件 类组件
写法 简洁,就是一个函数 啰嗦,要继承、要写render
状态管理 useState Hook this.state + setState
生命周期 useEffect 模拟 有专门的声明周期方法
this指向 不需要关心 要手动绑定或使用箭头函数
性能 通常更轻量 实例化开销稍大

注意:我曾经在一个项目里混用了函数组件和类组件,结果团队成员经常搞混this的绑定方式。后来统一改成函数组件,问题就没了。所以我的建议是——新项目统一用函数组件。

3.4 组件的挂载与渲染:组件是怎么跑到页面上的?

嗯,这里要注意。很多新手以为写了组件,它就会自动显示。其实不是的。

挂载(Mount),就是把组件插入到真实DOM中的过程。

React里,一切从 ReactDOM.createRoot() 开始:

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

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

这段代码做了三件事:

  1. 找到HTML里id为 root 的DOM节点
  2. 创建一个React根容器
  3. <App /> 组件渲染进去

渲染过程,简单来说是这样的:

  • React调用组件的函数(或类组件的render方法)
  • 得到虚拟DOM(Virtual DOM)树
  • 对比上一次的虚拟DOM(Diff算法)
  • 计算出最小的DOM操作
  • 更新真实DOM

说白了,React不是直接操作DOM的。它先在内存里算好「最优方案」,再一次性更新。这也是它快的原因。

我的经验:刚开始学React时,别纠结虚拟DOM的细节。你只要记住——React帮你做了DOM操作的优化。你只管写组件,它负责高效更新。

组件的生命周期(函数组件版):

useEffect 可以模拟类组件的生命周期:

import { useEffect } from 'react';

function MyComponent() {
  // 组件挂载时执行一次
  useEffect(() => {
    console.log('组件挂载了');
    
    // 组件卸载时执行
    return () => {
      console.log('组件卸载了');
    };
  }, []);

  // 依赖项变化时执行
  useEffect(() => {
    console.log('count变了');
  }, [count]);

  return <div>Hello</div>;
}

你看,useEffect 的第二个参数是依赖数组。空数组表示只在挂载时执行一次。有依赖项时,依赖变了就执行。返回的函数在卸载时执行。

记住这个规律:

  • useEffect(() => {}, []) → 相当于 componentDidMount
  • useEffect(() => {}, [dep]) → 相当于 componentDidUpdate
  • useEffect(() => { return () => {} }, []) → 相当于 componentWillUnmount

好了,这一章的内容就这些。JSX语法、组件化思想、函数组件与类组件的选择、组件的挂载与渲染——这四个概念,是React的基石。你把这章吃透了,后面学状态管理、路由、Hooks都会轻松很多。

下一章,咱们聊聊React的状态管理和事件处理。到时候我会分享一些我在实际项目中踩过的坑,保证有用。