So at the moment I am having to put my request / api logic directly into my components because what I need to do a lot of the time is set state based on the response I get from the back end.
Below is a function that I have on my settings page that I use to save the settings to recoil after the user hits save on the form:
const setUserConfig = useSetRecoilState(userAtoms.userConfig);const submitSettings = async (values: UserConfigInterface) => { try { const { data: {data} } = await updateUser(values); setUserConfig({ ...data }); } catch (error) { console.log('settings form error: ', error); }}
This works perfectly...I just dont want the function in my component as most of my components are getting way bigger than they need to be.
I have tried making a separate file to do this but I can only use the recoil hooks (in this instance useSetRecoilState
) inside of components and it just complains when I try and do this outside of a react component.
I have tried implementing this with recoils selector
and selectorFamily
functions but it gets kind of complicated. Here is how I have tried it inside of a file that has atoms / selectors only:
export const languageProgress = atom<LanguageProgress>({ key: "LanguageProgress", default: { level: 1, xp: 0, max_xp: 0 }})export const languageProgressUpdate = selectorFamily<LanguageProgress>({ key: "LanguageProgress", get: () => async () => { try { const { data: { data } } = await getLanguageProgress(); return data; } catch (error) { console.log('get language progress error'); } }, set: (params:object) => async ({set}) => { try { const { data: { data } } = await updateLanguageProgress(params); set(languageProgress, { level: data.level, xp: data.xp, max_xp: data.max_xp }); } catch (error) { console.log('language progress update error: ', error); } }});
What I want to do here is get the values I need from the back end and display it in the front which I can do in the selector function get but now I have 2 points of truth for this...my languageProgress atom will initially be incorrect as its not getting anything from the database so I have to use useGetRevoilValue
on the languageProgressUpdate
selector I have made but then when I want to update I am updating the atom and not the actual value.
I cannot find a good example anywhere that does what I am trying to here (very suprisingly as I would have thought it is quite a common way to do things...get data from back end and set it in state.) and I can't figure out a way to do it without doing it in the component (as in the first example). Ideally I would like something like the first example but outside of a component because that solution is super simple and works for me.