纯函数与受控/非受控组件
纯函数
纯函数使用函数式编程中的核心概念,主要有以下特征
- 确定性:每次传入相同值,必定返回相同结果
- 无副作用:不会改变外部变量,不会进行 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.保持父组件代码简洁。
*/
LinQiang·Shen