React技术疑问:用useRef存储初始值是否合规?有无更优方案?
React中存储useEffect初始路由的更优方案?
问题场景
我遇到一段React代码:
useEffect(() => { // 执行dispatch等逻辑 }, [dispatch, staticData, route]); // 遵循eslint react的exhaustive-deps规则
其中dispatch、staticData的引用始终不变,但route会因输入变化替换URL查询参数而频繁改变,导致useEffect被不必要地触发。
我考虑了两种方案:
- 方案1:禁用eslint的
react-hooks/exhaustive-deps规则,但担心后续维护人员修改useEffect时,无法感知这条规则的存在,风险较高。 - 方案2:用
useRef或useState存储初始路由值:
const initialRoute = useRef(route); // 也可以用const [initialRoute] = useState(route); useEffect(() => { // 使用initialRoute.current处理逻辑 }, [dispatch, staticData, initialRoute]);
该方案可行且能通过ESLint检查,但我想知道:是否存在比useRef更优的初始值存储方式?
解答
首先明确:useRef是当前场景下存储初始路由的最优方案之一,相比useState更贴合语义、性能更优,下面具体分析:
1. 为什么不推荐用useState存初始值?
useState(route)的初始值确实只会在组件首次渲染时生效,后续更新不会改变它,但useState的设计初衷是管理会变化的状态——你永远不会调用对应的setter来更新这个状态,用它存固定的初始值属于语义不符,而且没必要引入状态变量的额外开销。
2. useRef的优势
- 性能开销小:
useRef不会触发组件重渲染,只是存储一个可变的容器,完全适配“只需要初始化一次、后续不需要更新”的场景; - 语义清晰:React官方文档中,
useRef的典型用途之一就是存储不需要引发重渲染的可变值,初始路由正好符合这个定位; - 使用简便:通过
initialRoute.current即可访问初始值,代码逻辑清晰。
3. 更优雅的封装方式
如果需要在多个组件中复用“获取初始值”的逻辑,可以封装成自定义Hook,提升代码可读性和复用性:
function useInitialValue(value) { const ref = useRef(value); return ref.current; } // 在组件中使用 const initialRoute = useInitialValue(route); useEffect(() => { // 基于initialRoute执行逻辑 }, [dispatch, staticData, initialRoute]);
4. 另一种可选思路(不推荐,但可参考)
如果你的目标是让useEffect只在组件挂载时执行一次,也可以只保留不变的依赖dispatch、staticData,然后在useEffect内部直接使用首次渲染的route,同时添加明确的注释说明禁用ESLint规则的原因:
useEffect(() => { // 仅使用组件挂载时的初始route值,后续route变化不触发此逻辑 // eslint-disable-next-line react-hooks/exhaustive-deps }, [dispatch, staticData]);
但这种方式需要依赖注释来传达意图,相比用useRef存储初始值,维护风险更高,所以更推荐前者。
内容的提问来源于stack exchange,提问作者enguerranws
相关产品推荐
相关产品推荐

