I'm new to Recoil. I have an API that gives me user details, something like this
{
"name": userName,
"age" : 28,
"degree": MS,
"address": ...
}
I have a selector that gives me the API response. I would like to store each of these values to a recoil state/atom. So that I can use it across the application. We can't use an atom setter inside a selector. After getting the selector response from import, I was not able to set in the react component also. as it goes to the infinite loop. Please guide me.
export const userdetails = selector({
key: 'userdetails',
get: async ({ get }) => {
try {
const response = await axios.get('/user'));
const data = await response.data;
return data;
} catch (error) {
throw error;
}
}
});
this is my simple way to perfom that:
export const handleUserSearch = atom({
key:'handleUserSearch',
default: false
});
2. **create a selector wich handle that atom**
export const userDetails = selector({
key:'userDetails',
get : async ({ get }) => {
try{
const handleUserSearch = get(handleUserSearch);
let response;
if(handleUserSearch){
response = await axios.get('/user'));
return response.data;
}
return response;
}catch(error){
throw error;
}
})
//imports
import * as React from 'react';
import { useRecoilValue, useRecoilState } from 'recoil';
import {handleUserSearch, userDetails } from '../store';
//init variable for handle results and perfom search
const [handleUserSearch , sethandleUserSearch] = useRecoilState(handleUserSearch);
const userDetails = useRecoilValue(userDetails);
//use react hooks useEffet to handle changes
React.useEffet(()=>{
//check if userDeatails has data
if(userDetails !== undefined){
//there's data
//after getting data we stop searching
sethandleUserSearch(false);
}else{
//there's no data
}
},[sethandleUserSearch, userDetails]);
const handleSearch = () => {
//search data
sethandleUserSearch(true);
}
return (
<>
<button onClick={handleSearch} disable={handleUserSearch}>Search user</button>
</>
)
4.in other component
//imports
import * as React from 'react';
import { useRecoilValue} from 'recoil';
import {userDetails } from '../store';
//init variable for handle results
const userDetails = useRecoilValue(userDetails);
return (
<>
{userDetails &&
<p>{userDetails.name}</p>
}</>
)
i just test it and it work perfectly
Thanks @dommi10 it helps.
In my case, I also need a setter. which will update the user details (say which takes field 'name' and value 'userName2' as input and updates the recoilState. How can I write set in Selector? or should I have a SelectorFamily for it?
Yes i think. let's update the code below:
1. let's update own selector
export const userDetails = selector({
key:'userDetails',
get : async ({ get }) => {
try{
const handleUserSearch = get(handleUserSearch);
let response;
if(handleUserSearch){
response = await axios.get('/user'));
return response.data;
}
return response;
}catch(error){
throw error;
}
},
set: async( { set }, newValue)=>{
//update to server
try{
await axios.post('/updateUser',{newValue}));
}catch(error){
throw error;
}
//update local state
set(
handleUserSearch,
true
);
}});
2. to update component value
//imports
import * as React from 'react';
import { useRecoilState } from 'recoil';
import { userDetails } from './store';
//use recoil state to update user
const [ userDetails, setUserDetails ] = useRecoilState(userDetails);
//create local use state with hooks
const [name, setName ] = React.useState("");
//update function
const updateDetail = () => {
setUserDetails({...userDetails, name});
}
//handle change
const handleNameChange = (e, {value}) =>setName(value);
return(
<>
<input onChange={handleNameChange } placeholder='name'/>
<button onClick={updateDetail}>update</button>
</>
)
i think this can work.
for more info follow this link
Thanks @dommi10 this helps.