场景一:纯派生数据(只读展示)
使用场景 :根据 props 计算过滤、排序、格式化后的数据,仅用于展示。
设计原则 :不存入 state,直接在渲染时计算。计算量大时用缓存。
不使用缓存(简单场景)
javascript
// 函数组件
function ActiveUsers({ users }) {
const activeUsers = users.filter(u => u.active); // 每次渲染都执行
return <ul>{activeUsers.map(...)}</ul>;
}
// 类组件
class ActiveUsers extends React.Component {
render() {
const activeUsers = this.props.users.filter(u => u.active); // 每次渲染都执行
return <ul>{activeUsers.map(...)}</ul>;
}
}
使用缓存(昂贵计算场景)
javascript
// 函数组件(useMemo)
import { useMemo } from 'react';
function ExpensiveProcess({ data }) {
const processed = useMemo(() => {
return data.filter(u => u.active).sort(...).map(...); // 昂贵操作
}, [data]);
return <div>{processed}</div>;
}
// 类组件(memoize-one)
import memoize from 'memoize-one';
class ExpensiveProcess extends React.Component {
getProcessed = memoize((data) => {
return data.filter(u => u.active).sort(...).map(...);
});
render() {
const processed = this.getProcessed(this.props.data);
return <div>{processed}</div>;
}
}
场景二:初始值一次性使用(内部状态独立)
使用场景 :props 作为内部状态的初始值,后续用户可修改,父组件再改 prop 也不覆盖用户输入(如表单)。
设计原则 :仅在初始化时读取 props,不监听后续变化。
javascript
// 函数组件
function NameInput({ initialName }) {
const [name, setName] = useState(initialName);
return <input value={name} onChange={(e) => setName(e.target.value)} />;
}
// 类组件
class NameInput extends React.Component {
state = { name: this.props.initialName };
handleChange = (e) => this.setState({ name: e.target.value });
render() {
return <input value={this.state.name} onChange={this.handleChange} />;
}
}
场景三:响应 Props 变化(重置状态 / 执行副作用)
使用场景:
- 外部数据变化(如
list、userId)需要重置内部状态(页码、选中项)。 - 需要发起网络请求或操作 DOM。
设计原则 :用 useEffect(函数组件)或 componentDidUpdate(类组件)监听相关 prop,执行更新。
javascript
// 函数组件
function UserPanel({ userId }) {
const [page, setPage] = useState(1);
const [data, setData] = useState(null);
useEffect(() => {
setPage(1);
fetch(`/api?userId=${userId}`).then(res => res.json()).then(setData);
}, [userId]);
return <div>{data}</div>;
}
// 类组件
class UserPanel extends React.Component {
state = { page: 1, data: null };
componentDidUpdate(prevProps) {
if (prevProps.userId !== this.props.userId) {
this.setState({ page: 1 });
fetch(`/api?userId=${this.props.userId}`)
.then(res => res.json())
.then(data => this.setState({ data }));
}
}
render() {
return <div>{this.state.data}</div>;
}
}
快速决策
| 你的需求 | 对应场景 |
|---|---|
| 只根据 props 算个新值来显示 | 场景一 |
| 初始值来自 props,用户可改,父组件再改 props 不影响 | 场景二 |
| props 一变,内部状态就要重置 / 发起请求 | 场景三 |