组件与Hook中设置Recoil状态的行为差异及原因问询
Recoil状态在组件与Hook中设置的行为差异分析
问题核心
无法理解为何在组件中设置Recoil状态与在Hook中设置的行为存在差异。
问题详情
代码库中有一个仅包含逻辑、不渲染任何内容的组件:
const ComponentThatReturnsNothing = () => { const [, setSomeRecoilState] = useRecoilState(someStateAtom); useEffect(() => { window.Bridge = { // 以下函数由Android调用,代码运行在WebView中 functionThatSetsRecoilState: () => setSomeRecoilState('A_VALUE'); } }, []); return null; }
出于代码风格考虑,我将其改造为Hook,逻辑与原组件完全一致,仅按Hook规范修改了名称,并在App组件顶部调用(而非在App的render中使用),这引发了未预期的问题。
Recoil状态实际在SMSSender组件中使用:
const SMSSender = () => { const [someRecoilState] = useRecoilState(someStateAtom); return ( someRecoilState === 'B_VALUE' ? <FirstChild /> : <SecondChild /> ); }
组件树结构如下:
. └── App ├── ComponentThatReturnsNothing └── CustomerInitiate └── SMSSender
CustomerInitiate组件代码大致如下:
const CustomerInitiate = () => { const isConditionTrue = AndroidInterface.androidMethod(); // 设置Recoil状态前返回false,之后返回true return ( isConditionTrue ? <UnrelatedComponent /> : <SMSSender /> ); }
关键信息
当Android调用functionThatSetsRecoilState时,页面正在渲染SMSSender。调用后,androidMethod()开始返回true,意味着CustomerInitiate下次重渲染时会切换页面。
组件与Hook的行为差异
- 当
ComponentThatReturnsNothing作为组件存在时:Recoil状态设置为A_VALUE后,SMSSender能成功渲染SecondChild,SecondChild发起的API请求会在CustomerInitiate切换页面前完成。 - 改为Hook后:
CustomerInitiate会在SecondChild发起API请求前就渲染UnrelatedComponent,而UnrelatedComponent发起的API依赖于SecondChild的请求结果,因此引发依赖问题。
我的猜测
如果App的子组件订阅了Recoil状态,状态变化时不会重渲染整个App组件,因此CustomerInitiate不会立即重渲染;但如果App组件内的Hook订阅了Recoil状态,状态变化时会触发整个App组件重渲染,导致CustomerInitiate提前重渲染,不给SMSSender渲染SecondChild的机会。
更新
已通过将SecondChild及其渲染判断逻辑移至CustomerInitiate解决了问题,但仍想明确该问题的根本原因及上述猜测是否正确。
内容的提问来源于stack exchange,提问作者AviusX
相关产品推荐
相关产品推荐

