2、React基础回顾:JSX语法、组件化思想、Props与State、生命周期与Hooks入门

好,咱们正式开始React移动端适配之前,我得先带大家把React的基础再过一遍。你可能会想:「这些我都知道啊,干嘛还要讲?」

嗯,我理解。但说实话,移动端开发里很多坑,恰恰就出在这些基础概念上。比如JSX里一个不小心写错了条件渲染,整个页面白屏;再比如State更新不及时,导致动画卡顿。这些我都踩过。

所以这一章,咱们不搞花架子,就扎扎实实把JSX、组件、Props、State、生命周期和Hooks这几个核心概念捋一遍。我会结合移动端的实际场景来讲,保证你听完有收获。

2.1 JSX语法:不只是HTML的「糖」

JSX,说白了就是JavaScript的语法扩展。它让你能在JS里写类似HTML的代码。我第一次看到它时,心里想:「这不就是模板引擎吗?」后来才发现,完全不是一回事。

核心要点:JSX最终会被Babel编译成React.createElement()调用。所以它本质上是JS,不是HTML。

来看个移动端常见的例子——条件渲染一个加载状态:

function LoadingScreen({ isLoading, children }) {
  return (
    <div className="container">
      {isLoading ? (
        <div className="spinner">
          <span>加载中...</span>
        </div>
      ) : (
        children
      )}
    </div>
  );
}

这里有个坑,我当年在项目里遇到过:JSX里的注释要用{/* */},而不是HTML的。否则页面直接报错,找半天都找不到原因。

我的习惯:在JSX里写多行表达式时,一定要用括号包起来。比如上面那个三元表达式,不加括号的话,代码格式化后容易出问题。

另外,移动端开发中,JSX里经常要处理样式。记住:class要写成className,style要写成对象形式

// 正确写法
<div className="header" style={{ fontSize: '16px', color: '#333' }}>
  标题
</div>

2.2 组件化思想:搭积木的艺术

React的核心思想就是组件化。你想想看,一个移动端页面,从上到下可以分为:状态栏、导航栏、内容区、底部Tab。每一块都是一个独立的组件。

我建议你把组件分为两类:

  • 展示组件(Presentational):只负责UI呈现,不关心数据来源。比如一个按钮、一个卡片。
  • 容器组件(Container):负责数据获取和状态管理。比如一个用户列表页。

为什么要这么分?我在做一个电商App时,一开始把所有逻辑都写在一个组件里,结果改一个需求要改三处代码,差点崩溃。后来拆成容器+展示,维护成本直接降了一半。

注意:移动端组件要尽量「小」。一个组件超过200行代码,就该考虑拆分了。否则后面改起来,你连滚动条都不想拖。

2.3 Props与State:数据流动的两条腿

Props和State,是React数据管理的基石。我经常跟团队新人说:Props是父组件给你的「遗产」,State是你自己的「私房钱」

特性 Props State
来源 父组件传递 组件内部定义
可变性 不可变(只读) 可变(通过setState)
用途 配置组件 管理组件内部数据
更新触发 父组件重新渲染 调用setState或useState的更新函数

举个移动端的例子——一个可滑动的轮播图组件:

function Carousel({ images, autoPlay }) {
  // images 和 autoPlay 是 Props,由父组件传入
  const [currentIndex, setCurrentIndex] = useState(0);
  // currentIndex 是 State,组件自己管理

  useEffect(() => {
    if (autoPlay) {
      const timer = setInterval(() => {
        setCurrentIndex(prev => (prev + 1) % images.length);
      }, 3000);
      return () => clearInterval(timer);
    }
  }, [autoPlay, images.length]);

  return (
    <div className="carousel">
      <img src={images[currentIndex]} alt={`slide-${currentIndex}`} />
    </div>
  );
}

这里有个细节:State的更新是异步的。我曾经在移动端做下拉刷新时,直接写了setCount(count + 1),结果连续快速下拉时,计数总是少一次。后来改成setCount(prev => prev + 1)才解决。

避坑指南:如果你要基于当前State计算新值,一定要用函数式更新。这是React官方推荐的写法,也是我踩坑后养成的习惯。

2.4 生命周期与Hooks入门

类组件的生命周期,说复杂也复杂,说简单也简单。无非就是:挂载 → 更新 → 卸载三个阶段。

但说实话,自从Hooks出现后,我几乎不再用类组件了。为什么?因为Hooks让逻辑复用变得极其简单。

来看几个最常用的Hooks:

useState:管理组件状态

const [count, setCount] = useState(0);

这个不用多说,上面已经用过好几次了。

useEffect:处理副作用

useEffect可以看作是类组件中componentDidMountcomponentDidUpdatecomponentWillUnmount的合体。我一般用它来做三件事:

  • 数据请求(API调用)
  • 订阅/取消订阅(比如WebSocket)
  • 手动修改DOM(比如操作canvas)
useEffect(() => {
  // 组件挂载时执行
  fetchData();

  // 返回的清理函数,组件卸载时执行
  return () => {
    console.log('组件卸载了,清理工作');
  };
}, []); // 空数组表示只在挂载和卸载时执行

注意:useEffect的依赖数组一定要写全。我见过太多因为漏掉依赖导致bug的案例。如果你不确定,可以用ESLint的react-hooks/exhaustive-deps规则来检查。

useRef:保存可变引用

这个在移动端特别有用。比如你要获取一个DOM元素的尺寸,或者保存一个定时器的ID:

function AutoScrollList() {
  const listRef = useRef(null);

  useEffect(() => {
    // 滚动到底部
    listRef.current.scrollTop = listRef.current.scrollHeight;
  }, []);

  return <div ref={listRef} className="list">...</div>;
}

自定义Hooks:逻辑复用的终极武器

我建议你养成写自定义Hooks的习惯。比如,移动端经常要监听网络状态,我可以封装一个useNetworkStatus

function useNetworkStatus() {
  const [isOnline, setIsOnline] = useState(navigator.onLine);

  useEffect(() => {
    const handleOnline = () => setIsOnline(true);
    const handleOffline = () => setIsOnline(false);

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  return isOnline;
}

// 使用
function App() {
  const isOnline = useNetworkStatus();
  return <div>{isOnline ? '在线' : '离线'}</div>;
}

你看,这样写出来,逻辑清晰,复用性强。我在多个项目里都用过这个Hook,每次改需求只需要改一处。

总结一下:React基础其实不难,难的是在移动端场景下灵活运用。JSX要注意语法细节,组件要拆得够小,Props和State要分清楚,Hooks要善用。把这些基础打牢了,后面讲适配方案时你才能跟得上。

好,这一章就到这里。下一章我们开始真正进入移动端适配的世界——聊聊rem、vw、px这些单位到底怎么选。