如何在使用React.memo且不触发重渲染的组件中获取nextProps?
React.memo跳过重渲染时获取最新props的解决方案
问题本质
React.memo的比较函数返回true时,React会直接复用组件上次的渲染结果,不会执行组件函数体,组件内部闭包捕获的永远是上一次渲染的旧props,因此默认情况下只要组件不触发重渲染,就拿不到更新后的index值,这是React性能优化机制的固有逻辑。
你的需求是index更新时不触发组件重渲染,同时在组件回调中能拿到最新的index值,需要通过脱离React渲染闭包的存储方式实现。
最优解决方案(无需触发重渲染)
通过useRef可变引用传递index,利用ref引用不变、current属性可实时修改的特性,既不会触发重渲染,又能拿到最新值:
父组件改造
// 父组件内使用useRef包裹index const indexRef = useRef(初始index值); // index需要更新时,直接修改current属性,该操作不会触发任何渲染 indexRef.current = 新的index值; // 传递ref给子组件,ref引用永远不变,不会触发memo的重渲染判断 <TitleItems indexRef={indexRef} sel_mode={sel_mode} updateDataItem={updateDataItem} item={item} />
子组件改造
const TitleItems = props => { const { sel_mode, updateDataItem, indexRef, // 接收index的ref引用 item, } = props; const handleOnLongPress = () => { if (!sel_mode) { selModeON(); updateDataItem({ index: indexRef.current, // 直接读取current属性,永远是最新值 item: { ...item, checked: true, }, }); } }; return <>...</>; }; const areEqual = (prevProps, nextProps) => { // 仅比较影响UI渲染的属性,indexRef引用永远不变无需比较 return prevProps.sel_mode === nextProps.sel_mode && prevProps.item === nextProps.item; }; export default React.memo(TitleItems, areEqual);
其他可选方案
如果组件本身渲染成本极低,也可以直接调整memo的比较逻辑,允许index变化时不触发重渲染,同时在组件内用ref同步最新props:
const TitleItems = props => { const latestPropsRef = useRef(props); // 组件每次渲染时更新ref存储的最新props useEffect(() => { latestPropsRef.current = props; }, [props]); const handleOnLongPress = () => { const { sel_mode, updateDataItem, index, item } = latestPropsRef.current; // 后续业务逻辑不变 }; return <>...</>; }; const areEqual = (prevProps, nextProps) => { // 忽略index的变化,仅比较其他UI相关属性 return prevProps.sel_mode === nextProps.sel_mode && JSON.stringify(prevProps.item) === JSON.stringify(nextProps.item); };
注意:该方案仅在组件因其他属性更新触发重渲染时才会更新ref中的props,若只有index更新,ref不会同步最新值,因此优先推荐第一种ref传递方案。
注意事项
- 仅在用户交互回调、异步回调等不需要触发UI更新的场景下使用ref拿最新值,不要把ref的current属性作为useEffect、useMemo等hook的依赖项,会导致依赖检测失效。
- 如果你的组件UI本身需要展示index的值,必须触发重渲染才能更新UI,这种情况下不要跳过index的比较逻辑。
内容的提问来源于stack exchange,提问作者Zar Ni Ko Ko
相关产品推荐
相关产品推荐

