React哲学:保持组件纯粹 哈气就要哈得纯粹

纯粹函数的设计理念

什么是纯粹函数

纯粹函数的两大核心条件

条件1: 函数不修改被调用前就存在的变量与对象,只做纯粹的运算。

条件2: 保证函数相同的输入,就会有相同输出。

js 复制代码
//定义一个外部变量
let  num=0;

//纯粹函数
function add(x)
{//满足两大核心条件
 //条件1:不修改函数外的任何变量
 //条件2: 输入 x 固定,则输出必然是 x+1 
    return x+1;
}

//调用纯粹函数,传入外部的num
let a=add(num);
let b=add(num)

// num并未被修改,两次输入相同,得到的结果也相同
console.log(num,a) // 输出0 1
console.log(num,b) // 输出0 1

纯粹组件:React哲学

什么是纯粹的组件

纯粹组件的两大核心条件

react模仿纯粹函数的设计理念,提出纯粹组件的设计理念同样需要满足两个核心条件:

条件1:不修改组件渲染前存在的对象与变量。

条件2:相同的输出,返回相同的jsx

反例:什么样的组件不纯粹

条件1:组件内部对外部依赖值进行更改

条件2:多次渲染组件时输入相同,但是返回到jsx却不同

如果满足上诉两个任意一个条件,那么这个组件将不纯粹

jsx 复制代码
import React from 'react'
//定义一个外部变量
let num=0

function Child(){
// 组件修改外部依赖值
// 导致相同的输入下,每次返回的
  num++;
  return <div>{num}</div>
}

export default function App() {
  return (
    <div>
      <Child></Child>
      <Child></Child>
      <Child></Child>
    </div>
  )
}

为什么需要保持组件纯粹

  1. 保证组件渲染的独立性

所谓独立性:

如果组件渲染时修改了外部预先存在的变量会导致:

  • 后续依赖这些变量与对象的组件渲染产生不确定性,这就导致依赖同一变量的组件需要保证渲染的顺序。

  • 但是组件在浏览器中的渲染时机是不确定的。如果组件渲染结果,依赖组件间渲染的顺序。就会导致既定逻辑失效,从而产生错误。

所以我们要排除这种不确定性,使得react组件使用更加安全,让组件渲染之间的渲染逻辑更加独立

  1. 保证组件渲染的确定性

所谓确定性

确定性建立在独立性之上

  • 当组件渲染时独立地不影响外部组件的渲染逻辑,由此保证组件外部组件渲染的确定性,能够预先避免许多错误
  1. 没有保持纯粹性的反面案例
jsx 复制代码
// 全局变量(外部状态)
let globalCount = 0;

// 组件A:渲染时修改外部变量
function ComponentA() {
  globalCount += 1; // 修改外部变量
  return <div>组件A:{globalCount}</div>;
}

// 组件B:依赖同一个外部变量
function ComponentB() {
  return <div>组件B:{globalCount * 2}</div>;
}

// 父组件:同时渲染A和B
function Parent() {
  return (
    <div>
      <ComponentA />
      <ComponentB />
    </div>
  );
}
  • 理想顺序(A先渲染,B后渲染):globalCount 先变成 1,B渲染2 → 结果:A=1,B=2;
  • 实际可能的顺序(React调度导致B先渲染):B先读取 globalCount=0渲染0,再A把 globalCount 改成 1→结果:A=1,B=0;

保持纯粹 != 不可修改

局部突变

  1. 什么是局部突变

在react官方文档中的定义其实是"局部mutation",即在渲染时修改组件内部"刚刚创建对象或者变量"。

  • 这样的局部突变不会影响外部组件的渲染逻辑,只影响组件内部的逻辑。
  1. 利用局部突变保持组件的纯粹性
jsx 复制代码
// 全局变量(外部状态)
let globalCount = 0;

// 组件A:渲染时不修改外部变量
function ComponentA() {
  let Count=globalCount+1
  return <div>组件A:{Count}</div>;
}

// 组件B:依赖同一个外部变量,但是不直接修改外部变量
function ComponentB() {
  let Count=(globalCount+1)*2
  return <div>组件B:{Count * 2}</div>;
}

// 父组件:同时渲染A和B
function Parent() {
  return (
    <div>
      <ComponentA /> 
      <ComponentB />
    </div>
  );
}
  • 无论A,B谁先渲染,都改变不了渲染结果:A=1,B=2
  • 最终使组件重新保持"纯粹"

用"更新" 替换 "修改"

使用"状态"管理变量

  • 为了保证组件的纯粹性,并不意味着组件渲染依赖的外部变量完全就不能改变了。可以通过"状态"来管理外部变量。

"状态"管理变量的好处

  • 当变量需要被修改时,不再直接对其进行变更。而是等待组件渲染完成后,更新并将修改值传入组件中。由此保持组件渲染时的独立性与确定性
jsx 复制代码
import { useState } from 'react';

// 显示购物车数量的组件(纯粹组件:只依赖 props,无任何副作用)
function PureCartCount({ count }) {
  // 只读取 props,不修改任何外部数据,相同 props 必然渲染相同结果
  return <div>购物车数量:{count}</div>;
}

// 控制数量增减的组件(不直接修改数据,只发起更新请求)
function PureCountControls({ onAdd, onSubtract }) {
  // 不触碰任何变量,只通过父组件传入的函数发起"更新请求"
  return (
    <div>
      <button onClick={onSubtract}>-</button>
      <button onClick={onAdd}>+</button>
    </div>
  );
}

// 父组件:用状态管理变量,统一控制更新逻辑
function App() {
  // 用 useState 管理购物车数量(状态由 React 管控,初始值 1)
  const [cartCount, setCartCount] = useState(1);

  // 数量"更新"逻辑:生成新值,不修改原状态
  const handleAdd = () => {
    // 关键:不直接改 cartCount(如 cartCount +=1),而是通过 setCartCount 生成新值
    setCartCount(prevCount => prevCount + 1);
  };

  const handleSubtract = () => {
    // 生成新值(原 cartCount 保持不变,直到 React 触发重新渲染)
    setCartCount(prevCount => Math.max(1, prevCount - 1)); // 避免数量小于 1
  };

  return (
    <div>
      {/* 新状态通过 props 传入纯粹组件,组件只"读"不"写" */}
      <PureCartCount count={cartCount} />
      {/* 传递更新函数,让子组件发起更新请求 */}
      <PureCountControls onAdd={handleAdd} onSubtract={handleSubtract} />
    </div>
  );
}

export default App; 
相关推荐
Hilaku9 小时前
我用 Gemini 3 Pro 手搓了一个并发邮件群发神器(附源码)
前端·javascript·github
IT_陈寒9 小时前
Java性能调优实战:5个被低估却提升30%效率的JVM参数
前端·人工智能·后端
快手技术9 小时前
AAAI 2026|全面发力!快手斩获 3 篇 Oral,12 篇论文入选!
前端·后端·算法
颜酱9 小时前
前端算法必备:滑动窗口从入门到很熟练(最长/最短/计数三大类型)
前端·后端·算法
全栈前端老曹9 小时前
【包管理】npm init 项目名后底层发生了什么的完整逻辑
前端·javascript·npm·node.js·json·包管理·底层原理
HHHHHY9 小时前
mathjs简单实现一个数学计算公式及校验组件
前端·javascript·vue.js
boooooooom10 小时前
Vue3 provide/inject 跨层级通信:最佳实践与避坑指南
前端·vue.js
一颗烂土豆10 小时前
Vue 3 + Three.js 打造轻量级 3D 图表库 —— chart3
前端·vue.js·数据可视化
青莲84310 小时前
Android 动画机制完整详解
android·前端·面试
iReachers10 小时前
HTML打包APK(安卓APP)中下载功能常见问题和详细介绍
前端·javascript·html·html打包apk·网页打包app·下载功能