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; 
相关推荐
Bigger2 小时前
Tauri (22)——让 `Esc` 快捷键一层层退出的分层关闭方案
前端·react.js·app
大猫会长2 小时前
react中用css加载背景图的2种情况
开发语言·前端·javascript
编程修仙2 小时前
第一篇 VUE3的介绍以及搭建自己的VUE项目
前端·javascript·vue.js
search72 小时前
前端学习13:存储器
前端·学习
星月心城2 小时前
八股文-JavaScript(第一天)
开发语言·前端·javascript
政采云技术2 小时前
深入理解 Webpack5:从打包到热更新原理
前端·webpack
T___T2 小时前
从入门到实践:React Hooks 之 useState 与 useEffect 核心解析
前端·react.js·面试
山有木兮木有枝_2 小时前
当你的leader问你0.1+0.2=?
前端
前端程序猿之路2 小时前
模型应用开发的基础工具与原理之Web 框架
前端·python·语言模型·学习方法·web·ai编程·改行学it