This AsyncStorageHooks react custom hook
import {useState} from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
const AsyncStorageHooks = (key, value, mergedValue, keys) => {
const [data, setData] = useState('');
const [error, setError] = useState('');
const storeData = async () => {
try {
if (key && value) {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(key, jsonValue);
setData(jsonValue);
}
} catch (e) {
setError(e);
}
};
const getData = async () => {
try {
if (key) {
const jsonValue = await AsyncStorage.getItem(key);
setData(jsonValue != null ? JSON.parse(jsonValue) : '');
}
} catch (e) {
setError(e);
}
};
const mergeData = async () => {
try {
if (key && value && mergedValue) {
const jsonValue = JSON.stringify(value);
const mergedJsonValue = JSON.stringify(mergedValue);
await AsyncStorage.setItem(key, jsonValue);
await AsyncStorage.mergeItem(key, mergedJsonValue);
}
} catch (e) {
setError(e);
}
};
const removeData = async () => {
try {
if (key) {
await AsyncStorage.removeItem(key);
}
} catch (e) {
setError(e);
}
};
const getAllKeys = async () => {
let allKeys = [];
try {
allKeys = await AsyncStorage.getAllKeys();
setData(allKeys);
} catch (e) {
setError(e);
}
};
return {
data,
storeData,
getData,
removeData,
mergeData,
getAllKeys,
error,
};
};
export default AsyncStorageHooks;
this is my home component
const {data, error, getData, storeData, getAllKeys} =
useAsyncStorage('#word');
getData(); // this is works and use setData
storeData(); // this is works and use setData
getAllKeys();
console.log(data);
this works without any problems, they use the same page in the same state. It doesn't go into an infinite loop. The only getAllKeys dosen't works. Other functions works without any problems.
also side note: setData(allKeys); change to setData(allKeys + ''); or setData(JSON.stringify(allKeys)); stop to infinity loop why is that
You are getting an infinite loop because getAllKeys() is being called again and again. The first time it is called, there is this setData(keys) being called, which re-renders the component, because there is a state change.
When the component re-renders, getAllKeys() is called again, so setData(keys) is called, and it goes for ever. You would wanna use a useEffect to solve this problem, like so:
import {Text, View} from 'react-native';
import React, {useState, useEffect} from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
const Home = () => {
const [data, setData] = useState([]);
useEffect(()=>{
const getAllKeys = async () => {
let keys = [];
try {
keys = await AsyncStorage.getAllKeys();
setData(keys);
} catch (e) {
// read key error
}
};
getAllKeys();
},[])
console.log(data);
return (
<View>
<Text>hi</Text>
</View>
);
};
export default Home;
Related
For my posts
in component AboutUsers.jsx
const [users, setUsers] = useState([]);
if I write like this, it's working, I see posts in users:
in component AboutUsers.jsx
useEffect(()=> {
const getUsers = axios.get('https://jsonplaceholder.typicode.com/todos',{
params:{
_limit:limitPage,
_page:currentPage
}
})
.then(response => setUsers(response.data))
},[])
but I created other component PostMyServise.js with:
export default class PostMyServise {
static async getPost(limit=10, page=1) {
const result = await axios.get('https://jsonplaceholder.typicode.com/todos',{
params: {
_limit: limit,
_page: page,
}
})
.then(response => {
return response
})
return result;
}
}
And one yet component useCreatePosts.js:
export const usePosts = (callback) => {
const [isTrue, setIsTrue] = useState('')
const [error, setError] = useState('')
const createPost = async () => {
try {
setIsTrue(false);
await callback;
} catch (e) {
setError(e.message);
} finally {
setIsTrue(true);
}
}
return [createPost, isTrue, error];
}
export default usePosts;
I wrote this, and I see empty array in console.log(users):
I don't understand why array is empty
const [createPost, isTrue, error] = usePosts (async ()=> {
const response = await PostMyServise.getPost(limitPage, currentPage);
setUsers(response.data)
})
useEffect(() => {
createPost();
},[currentPage])
You are not calling the callback. You need to add the parentheses.
const createPost = async () => {
try {
setIsTrue(false);
await callback();
} catch (e) {
setError(e.message);
} finally {
setIsTrue(true);
}
}
I feel like something about your code is over-engineered and too complex but that's outside the scope of the question. This change will at least get it working. Also, I suggest changing the name of isTrue and setIsTrue to something more meaningful as those names do not tell you what they are for.
I'm trying to understand how useEffect works.
I have two callApi: "callApiDialer" is based on response of "callApiManager", for get id from list.
But "currentLeadId" state at first called obviously is null.
How can call "callApiDialer" when currentLeadId is not null?
import React, { useState, useEffect } from 'react';
const [loading, setLoading] = useState(true);
const [apiManager, setApiManager] = useState([]);
const [apiDialer, setApiDialer] = useState([]);
const [currentLeadId, setCurrentLeadId] = useState(null);
// CALL API
const callApiManager = async () => {
try {
const response = await api.get(`/api/manager/op/1`);
setCurrentLeadId(response.data.dialer_list[0].id);
setApiManager(response.data);
} catch (err) {
alert("fetchApiManager " + err.response.status);
}
}
const callApiDialer = async () => {
try {
const response = await api.get(`/api/manager/lead/${currentLeadId}`);
setApiDialer(response.data.lead);
setLoadingModal(false);
} catch (err) {
alert("fetchApiSources " + err.response.status);
}
}
useEffect(() => {
callApiManager();
}, [])
useEffect(() => {
console.log(currentLeadId); // <-- here get first null and after currentLeadId
if(currentLeadId) {
callApiDialer();
setLoading(false);
}
}, [currentLeadId])
You could have just one function that call both, therefore there would be only one useEffect.
// CALL API
const callBothApisAtOnce= async () => {
try {
const op = await api.get(`/api/manager/op/1`);
const response = await api.get(`/api/manager/lead/${op.data.dialer_list[0].id}`);
// rest of your logic...
} catch (err) {
alert("err" + err);
}
}
useEffect(() => {
callBothApisAtOnce()
}, [])
you can use axios's promise base functionality
axios.get(`/api/manager/op/1`).then(res => {
setCurrentLeadId(response.data.dialer_list[0].id);
setApiManager(response.data);
axios.get(`/api/manager/lead/${response.data.dialer_list[0].id}`).then(res1 =>{
setApiDialer(res1.data.lead);
setLoadingModal(false);
}
}
I do not understand what I am missing here, I would be very grateful for your help!
I'm getting to my "Test" functional component, from another functional component, by the command history.push (urlState).
"urlState" is an object, which I check its values in the useEffect function of the "Test" component.
Based on the values in urlState, I decide whether to execute "setRequestNumber" and "setRequestSubNumber", and which values to send to them.
But the set functions do not work !!
What am I doing wrong ??
(I want useEffect to run only once, so I left the dependencies array-blank.)
Here is my code-
import React, { useState, useEffect } from "react";
import {URL} from "../../config/Constants"
const Test = (props) => {
const [requestNumber, setRequestNumber] = useState(0);
const [requestSubNumber, setRequestSubNumber] = useState(1);
const getRequestDetails = async (fetchURL) => {
try {
const response = await fetch(fetchURL);
if (!response.ok) {
throw new Error("something went wrong!");
}
const body = await response.json();
const result = body.results;
console.log(result); //result will be rendered instead of <h1>Hi there!</h1>
} catch (error) {}
};
const getNextRequestCounter = async () => {
try {
const response = await fetch(`${URL}/requests/requestCounter`);
if (!response.ok) {
throw new Error("something went wrong!");
}
const body = await response.json();
const result = body.results[0];
setRequestNumber(result);
} catch (error) {
}
};
useEffect(() => {
var urlState = {
request: 1,
subRequest: 2,
isNewRequest: false,
originalSubRequest: 1,
}; // That what I have in props.location.state;
var fetchURL = "";
if (urlState.isNewRequest) {
getNextRequestCounter();
fetchURL = `${URL}/requests/${requestNumber}/${requestSubNumber}`;
} else {
setRequestNumber(urlState.request);
setRequestSubNumber(urlState.subRequest);
fetchURL = `${URL}/requests/${requestNumber}/${urlState.originalSubRequest}`;
}
getRequestDetails(fetchURL);
}, []);
return <h1>Hi there!</h1>;
};
export default Test;
Thank you!
It seems like react-query is a quiet popular so, I trying to add react-query to my exist codes.
the code below is the exist codes. it uses hooks (useEffect & useState), axios and returns response data.
import { useState, useEffect } from 'react';
import { apiProvider } from 'services/modules/provider';
import { useLoading } from 'components/Loading/Loading';
export const useCommonApi = (url: string, params?: any) => {
const [_, setLoading] = useLoading();
const [State, setState] = useState<any>();
useEffect(() => {
try {
const getState = async () => {
const result: any = await apiProvider.get('common/' + url, params);
let resultData = result.data || [];
if (url === 'available_countries') {
resultData = resultData.map((o: any) => {
return { value: o.id, label: o.name };
});
}
setState([...resultData]);
return resultData;
};
getState();
} catch (e) {
console.error(e);
}
}, []);
return State;
};
Here is the my new codes for react-query. I am trying to convert code above into react-query as below.
import { useState, useEffect } from 'react';
import { apiProvider } from 'services/modules/provider';
import { useLoading } from 'components/Loading/Loading';
import axios from 'axios';
import { useQuery } from 'react-query';
export const useCommonApi_adv = (url: string, params?: any) => {
const [_, setLoading] = useLoading();
const [State, setState] = useState<any>();
const { isLoading, error, data } = useQuery('fetchCommon', () =>
axios('/api/v1/admin/common/' + url).then( (res) :any => {
return res.data
})
)
if (isLoading) return 'Loading...'
let resultData = data.data || [];
if (url === 'available_countries') {
resultData = resultData.map((o: any) => {
return { value: o.id, label: o.name };
});
}
setState([...resultData]);
return State;
};
the my new codes(react-query) prints "too many render" when it is executed.
What did I wrong with it? any help please
You are calling your state update function setState outside of an useEffect. This will run on the first render, update the state, which in turn triggers a rerender, update the state again and you end up in an endless loop. You probably want to wrap that logic into useEffect and only run it if data changes.
import { useState, useEffect } from 'react';
import { apiProvider } from 'services/modules/provider';
import { useLoading } from 'components/Loading/Loading';
import axios from 'axios';
import { useQuery } from 'react-query';
export const useCommonApi_adv = (url: string, params?: any) => {
const [_, setLoading] = useLoading();
const [State, setState] = useState<any>();
const { isLoading, error, data } = useQuery('fetchCommon', () =>
axios('/api/v1/admin/common/' + url).then( (res) :any => {
return res.data
})
)
useEffect(() => {
let resultData = data.data || [];
if (url === 'available_countries') {
resultData = resultData.map((o: any) => {
return { value: o.id, label: o.name };
});
}
setState([...resultData]);
}, [data])
if (isLoading) return 'Loading...'
return State;
};
I am executing useEffect() to update a state with JSON data. However the fetch request sometimes fails, so I want to re-execute the useEffect hook if that happens:
...
import React, {useState, useEffect} from 'react';
import {getJsonData} from './getJsonData';
const myApp = () => {
var ErrorFetchedChecker = false;
const [isLoading,setIsLoading] = useState(true);
const [data,setData] = useState(null);
const updateState = jsonData => {
setIsloading(false);
setData(jsonData);
};
useEffect(() => {
//console.log('EXECUTING');
getJsonData().then(
data => updateState(data),
error => {
Alert.alert('DATA FETCHING ERROR !', 'Refreshing ?...');
ErrorFetchedChecker = !ErrorFetchedChecker;
//console.log('LOG__FROM_CountriesTable: Executed');
},
);
}, [ErrorFetchedChecker]);//Shouldn't the change on this variable
//be enough to re-execute the hook ?
return (
<View>
<Text>{state.data.title}</Text>
<Text>{data.data.completed}</Text>
</View>
);
}
Here's the getJsonData() function just in case:
export async function getJsonData() {
try {
let response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
let responseJson = await response.json();
return responseJson;
} catch (error) {
throw error;
// Also, is this the correct way to handle the error ?
// As the Alert in useEffect goes off either ways.
// If not, advise me on how the error should be handled.
}
}
This will work
const myApp = () => {
const [errorFetchedChecker, setErrorFetchedChecker] = useState(false);
const [isLoading,setIsLoading] = useState(true);
const [data,setData] = useState(null);
const updateState = jsonData => {
setIsloading(false);
setData(jsonData);
};
useEffect(() => {
//console.log('EXECUTING');
getJsonData().then(
data => updateState(data),
error => {
Alert.alert('DATA FETCHING ERROR !', 'Refreshing ?...');
setErrorFetchedChecker(c => !c);
//console.log('LOG__FROM_CountriesTable: Executed');
},
);
}, [errorFetchedChecker]);
return (
<View>
<Text>{state.data.title}</Text>
<Text>{data.data.completed}</Text>
</View>
);
}
import React, { useState, useRef, useEffect } from "react";
import { Text, View, TextInput } from "react-native";
const App = () => {
var ErrorFetchedChecker = false;
const [isLoading, setIsLoading] = useState(true);
const [data, setData] = useState(null);
const updateState = (jsonData) => {
setIsLoading(false);
setData(jsonData);
};
useEffect(() => {
//console.log('EXECUTING');
getJsonData()
.then((data) => {
console.log("1. Successful, just received the data from our promise");
updateState(data);
console.log("2. We set our data because we received it successfully");
return { alreadySet: true };
})
.catch((e) => {
console.log("1. We failed to gather data in our initial promise");
console.log("2. Attempting to rerun initial promise");
return getJsonData();
})
.then((data) => {
if (data.alreadySet) {
console.log(
"3. Did not attempt to retry because we are already successful"
);
} else {
console.log("3. Our second attempt succeeded");
updateState(data);
console.log("4. Set our data on our second attempt");
}
})
.catch((e) => {
console.log("3. Both attempts have failed");
});
}, []); //Shouldn't the change on this variable
//be enough to re-execute the hook ?
return (
<View>
<Text>{data ? <Text>{data.title}</Text> : null}</Text>
</View>
);
};
export async function getJsonData() {
try {
let response = await fetch("https://jsonplaceholder.typicode.com/todos/1");
let responseJson = await response.json();
return responseJson;
} catch (error) {
throw error;
// Also, is this the correct way to handle the error ?
// As the Alert in useEffect goes off either ways.
// If not, advise me on how the error should be handled.
}
}
export default App;