RN组件中 `observer`、`memo`、普通组件与函数形式

下面说明三种组件包装方式、数据如何流动,以及 function 与箭头函数的区别。


1. 三种写法,三种职责

项目 Home 页里同时出现三种写法,它们解决的是不同问题:

// observer — 订阅 MobX,数据变了要更新
const HomeContent = observer(function HomeContent({ navigation }) {
    const deviceState = useDeviceState()
    return <HomeView deviceTitle={...} statusSubtitle={...} />
})

// 普通组件 — 只吃 props,负责画 UI
const HomeView = ({ deviceTitle, statusSubtitle, ... }) => {
    return ( ... )
}

// memo — props 没变时,跳过重复渲染
const NavBar = memo(({ title, subtitle, onBack, onMore }) => {
    return ( ... )
})
写法 解决什么问题 典型场景
observer MobX 变了,组件要重新 render useDeviceState() 的页面/容器
普通组件 只根据 props 渲染 HomeView 等展示层
memo 父 render 了,但 props 没变 → 不重绘 NavBarFunctionCard 等叶子组件

决策流程:

组件里会读 MobX store 吗?
  ├─ 是 → 用 observer
  └─ 否 → 只是展示 props?
        ├─ 是,且父组件常 render、props 常不变 → 用 memo
        └─ 否 → 普通函数组件即可

2. 数据怎么流动:为什么 HomeContent 变了,HomeView 也会变

React 和 MobX 是两套更新机制。useState 变了 React 知道;MobX store 变了,React 默认不知道。所以谁读了 MobX,谁就要包 observer

HomeContent 读了 store,必须包 observerHomeView 不读 store,只收 props,不需要 observer,但照样会更新:

MobX store 变化
       ↓
HomeContent(observer)重新 render
       ↓
算出新的 deviceTitle、statusSubtitle 等
       ↓
<HomeView deviceTitle={新值} ... />   ← props 变了
       ↓
HomeView 重新 render                    ← 父 render,子跟着 render

可以把 HomeContent 想成「看仓库的人」,HomeView 想成「只显示上级传来数字的板子」。仓库变了 → 看仓库的人更新 → 传新 props → 板子内容变了。板子不用自己订阅 MobX。

observer 管的是「MobX 变了,该重新 render」,不是「子组件也要包 observer 才会更新」。只有组件自己读 store 时,才需要在它上面包 observer

memo 对比:

  • HomeContent 变 → HomeView 变(父传新 props)
  • HomeContent 变 → NavBar 可能不变(若 titlesubtitle 未变,memo 会拦住)

注意:若每次 render 都传新函数,如 onMore={() => navigation.navigate('Settings')}NavBarmemo 会失效,需要用 useCallback 稳定引用。

Home 页完整结构:

MobX deviceState
       ↓
HomeContent(observer)— 读数据、算逻辑
       ↓ props
HomeView(普通组件)— 组装布局
       ↓ props
NavBar / FunctionCard(memo)— 纯 UI,可跳过无效 render

3. 函数形式:function HomeContent({ ... }) => 的区别

这两种写法都是合法的 React 函数组件,功能上等价,区别在 JavaScript 语法和习惯,与 observer / memo 无关。

命名函数:

const HomeContent = observer(function HomeContent({ navigation }) {
    // ...
})

箭头函数:

const HomeView = ({
    navigation,
    deviceTitle = 'OZ601 Ultra',
    statusSubtitle = 'Standby',
    isOffline = false,
    onMenuPress = () => {},
}) => {
    // ...
}
function 组件名() const 组件名 = () =>
函数名 直接写在 function 名字来自变量
DevTools 显示 HomeContent,调试清晰 有时显示 Observer 或匿名
this 有自己的 this 继承外层(函数组件里基本不用)

项目里常见组合:observer 包容器时用 命名函数(DevTools 好看);展示组件、小组件用 箭头函数(更短)。团队统一用一种也可以,不是硬性规定。


4. 参数写法:解构与默认值

HomeView 参数里的大括号不是特殊语法,而是 props 解构 + 默认值

const HomeView = ({
    navigation,
    deviceTitle = 'OZ601 Ultra',   // 没传时用默认值
    statusSubtitle = 'Standby',
    onMenuPress = () => {},
}) => { ... }

等价于:

function HomeView(props) {
    const navigation = props.navigation
    const deviceTitle = props.deviceTitle ?? 'OZ601 Ultra'
    // ...
}

解构写法更简洁,箭头函数和 function 都可以这样写

function HomeView({ deviceTitle = 'xxx' }) { ... }   // 完全等价
const HomeView = ({ deviceTitle = 'xxx' }) => { ... }

5. 团队实践与一句话总结

推荐分层:

  • index.jsobserver 容器,读 store、算数据
  • XxxView.js:普通展示组件,只收 props
  • components/:可复用 UI,按需 memo

三句话记住:

  1. 谁读 MobX,谁包 observer
  2. 只吃 props 的组件,父 render 就会跟着变,不必包 observer
  3. function=> 是写法差异;{ navigation, title = '...' } 是解构 + 默认值,两种函数形式都能用
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容