Skip to content

纯函数与受控/非受控组件

纯函数

纯函数使用函数式编程中的核心概念,主要有以下特征

  • 确定性:每次传入相同值,必定返回相同结果
  • 无副作用:不会改变外部变量,不会进行 I/O 操作(如网络请求、文件读写)。

TIP

  • 不依赖外部变量(如全局变量、系统时间)
  • 不修改传入的参数(如直接修改对象属性)
  • 不触发可观察的副作用(如日志输出、DOM 操作)

纯函数有个好处,是输入即确认输出结果,这有利于编写单元测试,只要有大量的测试用例就能保证代码的稳定性和可维护性,便于脱离外部环境直接编写代码逻辑。

js
// 纯函数
function add(a, b) {
  return a + b;
}

// 非纯函数
let c = 1;
function impureAdd(a) {
  return a + c; // 依赖外部变量
}

// 非纯函数(有副作用)
function updateDOM() {
  document.getElementById("demo").textContent = "Changed"; // 修改DOM
  // or 发起网络请求
  fetch("xxx")
    .then((res) => console.log(res))
    .catch((err) => console.log(err));
}
// 纯函数
function add(a, b) {
  return a + b;
}

// 非纯函数
let c = 1;
function impureAdd(a) {
  return a + c; // 依赖外部变量
}

// 非纯函数(有副作用)
function updateDOM() {
  document.getElementById("demo").textContent = "Changed"; // 修改DOM
  // or 发起网络请求
  fetch("xxx")
    .then((res) => console.log(res))
    .catch((err) => console.log(err));
}

纯函数一般用于我们编写工具函数、受控组件

  • 例如:一个需要处理映射关系的文案
js
function getFormatterLabel(key) {
  const TextMap = { mode: "模式", gear: "档位" };
  return TextMap[key] ?? "--";
}
function getFormatterLabel(key) {
  const TextMap = { mode: "模式", gear: "档位" };
  return TextMap[key] ?? "--";
}
  • 例如:一个 React 受控弹窗组件
js
function renderDialog(props) {
  const { visible, title } = props;
  visible && return null // 不显示
  return (
    <View>
      <Text>{title}</Text>
    </View>
  );
}
function renderDialog(props) {
  const { visible, title } = props;
  visible && return null // 不显示
  return (
    <View>
      <Text>{title}</Text>
    </View>
  );
}

受控组件与非受控组件

受控组件(纯 UI 显示)

  • 是否受父组件控制的子组件,纯受控组件:所有行为都有父组件传入的值决定
js
function renderDialog(props) {
  const { visible, title } = props;
  visible && return null // 不显示
  return (
    <View>
      <Text>{title}</Text>
    </View>
  );
}
function renderDialog(props) {
  const { visible, title } = props;
  visible && return null // 不显示
  return (
    <View>
      <Text>{title}</Text>
    </View>
  );
}

非受控组件(有自己内部状态管理)

  • 组件不受外部状态影响,只有通过暴露方法方式给父组件改变内部状态,其余由自身内部管理状态
js
function renderDialog(props) {
  const [visible ,setVisible] = useState(false)
  const [title ,setTitle] = useState("标题1")
  const handleChangeTitle = ()=>{
    setTitle("标题2")
  }
  visible && return null // 不显示
  return (
    <ListItem
      title={title}
      showSeparator={false}
      value={dialogValue}
      onPress={handleChangeTitle}
    />
  );
}
function renderDialog(props) {
  const [visible ,setVisible] = useState(false)
  const [title ,setTitle] = useState("标题1")
  const handleChangeTitle = ()=>{
    setTitle("标题2")
  }
  visible && return null // 不显示
  return (
    <ListItem
      title={title}
      showSeparator={false}
      value={dialogValue}
      onPress={handleChangeTitle}
    />
  );
}

混合模式(受控与非受控组件结合)

  • 强烈建议业务开发中使用该模式,即符合组件“单一职责原则”,也能有效减少父组件的状态管理负担,同时保持组件的封装性和可维护性。
js
export default function ClearCodeWithDialog(props) {
  const [isDialog, setIsDialog] = useState(false);
  const handleOpen = () => {
    setIsDialog(true);
  };
  const handleClose = () => {
    setIsDialog(false);
  };
  const handleClear = () => {
    setIsDialog(false);
    props.onClear();
  };
  return (
    <>
      {/* 控制器清码 */}
      <ListItem title={"控制器清码"} showSeparator={false} onPress={handleOpen} />
      {/* 弹窗 */}
      <MessageDialog
        visible={isDialog}
        title={"控制器清码"}
        message={"控制器清码提示"}
        buttons={[
          {
            text: "cancel",
            callback: handleClose
          },
          {
            text: "清码",
            backgroundColor: { bgColorNormal: "blue" },
            callback: handleClear
          }
        ]}
        onDismiss={handleClose}
      />
    </>
  );
}

/*
1.弹窗状态纯粹由用户交互触发(如点击按钮)。
2.父组件仅需响应业务逻辑(如 onClear),不关心弹窗开闭细节。
3.保持父组件代码简洁。
*/
export default function ClearCodeWithDialog(props) {
  const [isDialog, setIsDialog] = useState(false);
  const handleOpen = () => {
    setIsDialog(true);
  };
  const handleClose = () => {
    setIsDialog(false);
  };
  const handleClear = () => {
    setIsDialog(false);
    props.onClear();
  };
  return (
    <>
      {/* 控制器清码 */}
      <ListItem title={"控制器清码"} showSeparator={false} onPress={handleOpen} />
      {/* 弹窗 */}
      <MessageDialog
        visible={isDialog}
        title={"控制器清码"}
        message={"控制器清码提示"}
        buttons={[
          {
            text: "cancel",
            callback: handleClose
          },
          {
            text: "清码",
            backgroundColor: { bgColorNormal: "blue" },
            callback: handleClear
          }
        ]}
        onDismiss={handleClose}
      />
    </>
  );
}

/*
1.弹窗状态纯粹由用户交互触发(如点击按钮)。
2.父组件仅需响应业务逻辑(如 onClear),不关心弹窗开闭细节。
3.保持父组件代码简洁。
*/