Recoil技术疑问:Selector调用API后设置Atom值及无参获取数据
解决方案
核心问题拆解
- Recoil 的 Selector
get函数是纯函数,禁止直接修改 Atom,必须通过可写 Selector 或回调函数处理状态更新。 - AtomFamily 必须接收参数才能生成对应实例,无法直接无参调用,需要用普通 Atom/Selector 封装固定参数逻辑实现无参获取。
方案一:自动同步数据 + 无参获取
通过让目标 Atom 依赖 Selector,实现数据自动同步,同时用普通 Atom 替代 AtomFamily 实现无参调用:
// 修正原SelectorFamily的变量名错误 export const downloadDataResultsQuery = selectorFamily<Downloads[], string[]>({ key: 'downloadDataResultsQuery', get: (names) => ({ get }) => { // 修复:crateName → name const data = get(waitForAll(names.map((name) => downloadDataResultQuery(name)))); return data; }, }); // 定义普通Atom,存储固定参数的查询结果(这里默认传空数组,可根据需求修改) export const defaultDownloadDataState = atom<Downloads[]>({ key: 'defaultDownloadDataState', default: downloadDataResultsQuery([]), }); // 让downloadData自动同步查询结果,同时支持手动修改 export const downloadData = atom<Downloads[]>({ key: 'downloadData', default: (get) => get(defaultDownloadDataState), });
使用方式:
// 无参获取数据 const downloadDataResults = useRecoilValue(defaultDownloadDataState); // 或者直接获取同步后的downloadData const downloadData = useRecoilValue(downloadData);
方案二:手动触发 + 无参获取
适合需要主动触发数据更新的场景,通过useRecoilCallback处理状态更新,用 Selector 封装无参获取逻辑:
// 保留原Atom定义 export const downloadData = atom({ key: 'downloadData', default: [], }); // 修正原SelectorFamily export const downloadDataResultsQuery = selectorFamily<Downloads[], string[]>({ key: 'downloadDataResultsQuery', get: (names) => ({ get }) => { const data = get(waitForAll(names.map((name) => downloadDataResultQuery(name)))); return data; }, }); // 存储当前查询用的names export const currentDownloadNames = atom<string[]>({ key: 'currentDownloadNames', default: [], }); // 无参获取的Selector,自动关联当前names的查询结果 export const currentDownloadData = selector<Downloads[]>({ key: 'currentDownloadData', get: ({ get }) => { const names = get(currentDownloadNames); return get(downloadDataResultsQuery(names)); }, });
组件中使用:
// 手动触发数据查询并更新downloadData const fetchDownloadData = useRecoilCallback(({ set, get }) => (names: string[]) => { set(currentDownloadNames, names); const data = get(downloadDataResultsQuery(names)); set(downloadData, data); }); // 无参获取当前结果 const downloadDataResults = useRecoilValue(currentDownloadData); // 调用示例:触发查询 fetchDownloadData(['crate1', 'crate2']);
方案三:可写Selector处理更新逻辑
通过可写 Selector 同时实现触发查询和状态更新:
export const downloadData = atom({ key: 'downloadData', default: [], }); export const downloadDataResultsQuery = selectorFamily<Downloads[], string[]>({ key: 'downloadDataResultsQuery', get: (names) => ({ get }) => { const data = get(waitForAll(names.map((name) => downloadDataResultQuery(name)))); return data; }, }); // 可写Selector:设置时传入names,自动查询并更新downloadData export const fetchAndSetDownloadData = selector<Downloads[]>({ key: 'fetchAndSetDownloadData', get: ({ get }) => { // 默认返回空数组查询结果 return get(downloadDataResultsQuery([])); }, set: ({ set, get }, names: string[]) => { const data = get(downloadDataResultsQuery(names)); set(downloadData, data); }, });
组件中使用:
// 无参获取downloadData的值 const downloadDataResults = useRecoilValue(downloadData); // 触发查询并更新 const triggerFetch = useSetRecoilState(fetchAndSetDownloadData); triggerFetch(['crate1', 'crate2']);
内容的提问来源于stack exchange,提问作者Pytan
相关产品推荐
相关产品推荐

