Recoil中使用selectorFamily调用API无法同步数据到atom如何解决
问题原因
你当前的代码只实现了用selectorFamily拉取接口数据,没有建立接口返回数据和sourceDetailsState atom的同步逻辑,同时selectorFamily的set方法也未正确实现数据写入逻辑,因此atom始终保持默认的空对象值。
修复方案
你可以根据实际业务场景选择以下任意一种方案:
方案1:组件内手动同步(改造成本最低)
直接在组件中监听selectorFamily的返回值,拿到数据后主动写入atom,新增useEffect逻辑即可:
import { useEffect } from 'react'; // 原有代码保持不变 const sourceDetailsData = useRecoilValue( getSourceDetails(sourceLoaderData.id as number), ); const [sourceDetailsStateData, setData] = useRecoilState(sourceDetailsState); // 新增同步逻辑 useEffect(() => { if (sourceDetailsData) { setData(sourceDetailsData); } }, [sourceDetailsData, setData]);
方案2:绑定atom默认值(无需手动同步,推荐多ID场景使用)
如果你需要按ID存储多份数据源,应该把单个atom替换为atomFamily,直接绑定默认值为对应selectorFamily的返回结果,无需额外写同步逻辑:
第一步:修改atom定义
// 把原有sourceDetailsState替换为atomFamily export const sourceDetailsState = atomFamily<Partial<ISourceConfigurationEdit>, number>({ key: 'getSourceDetailsState', default: (id: number) => getSourceDetails(id), });
第二步:修改selectorFamily的set方法(如果需要自定义更新逻辑)
export const getSourceDetails = selectorFamily({ key: 'SourceLoaderSourceDetails', get: (id: number) => async () => { try { const { data } = await load(`/sourceloader/getSourceDetails/${id}`); return convertTableDataMapToArray(data); } catch (e) { console.error(e); return {}; } }, // 修改set逻辑,支持按ID更新对应atom的值 set: (id: number) => ({ set }, newValue) => { set(sourceDetailsState(id), newValue); }, });
第三步:组件内直接使用
const [sourceDetailsStateData, setData] = useRecoilState(sourceDetailsState(sourceLoaderData.id as number));
注意事项
- 使用异步selector时,组件外层需要包裹
Suspense组件处理加载态,否则会触发运行时报错 - 如果不需要修改接口返回的源数据,可直接使用
useRecoilValue(getSourceDetails(id))拿数据,不需要额外维护一层atom,减少冗余代码 - 单个atom仅适合存储单ID数据,多ID场景必须用
atomFamily避免数据覆盖
内容的提问来源于stack exchange,提问作者arunmmanoharan
相关产品推荐
相关产品推荐

