How to stop multiple Firebase events callback on(Value,snapshot) - react-native

I am new to firebase. I want to get realtime data when a user click on any pushKey. When i click on another node i get previous node data also.I dont know where to use ref.off('value',listener). please help me out. Anyhelp will be appreciated
export const fetchCurrentCircleLocation = pushKey => {
return async dispatch => {
let ref = firebase.database().ref(Circles/${pushKey}/members);
let listener = await ref.on("value", snapshot => {
// console.log("circleLocation", snapshot.val());
dispatch({
type: FETCH_CURRENT_GROUP_CIRCLE_LOCATION,
payload: snapshot.val()
});
});
};
};

Try using once. It will go through your database items only once. You don't need to remove listener.
ref.once("value", function (snapshot) {
snapshot.forEach((child) => {
console.log(child.val())
});
});

Related

Can I return value from action creator using redux-thunk?

I've seen a lot of examples of async action creators, but they all do some sort of fetching and pushing data to redux store and return nothing. I need another logic that looks something like:
const createUserAction = (user) => {
firestore().collection('users').add(user)
.then(result => {
dispatch({type: 'SET_USER', payload: {...user, id: result.id}})
})
}
I need to return result.id from createUserAction to navigate to page that displays user by his id. In my imagine it should work like
createUserAction({name: John}).then(id => navigation.navigate('UserDetailPage', {userId: id}))
I don't know how to implement that and I'll be glad if somebody can help
Returning values from action creators is a No-Go. The solution for this scenario that I've used and think is better is to do the redirect in the async action itself:
// afterCreation = callback function with one argument, the created user
const createUserAction = async (user, afterCreation) => {
const createdUser = await firestore().collection('users').add(user);
dispatch({type: 'SET_USER', payload: {...user, id: createdUser.id}});
afterCreation(createdUser);
};
createUserAction(
{name: John},
// Pass callback to action creator
(user) => navigation.navigate('UserDetailPage', {userId: user.id})
);

Unable to set useState variable in async method and console log it

Im working with my friends on a app project and we find an issue many times when we tring to set a use state and the console log the variable, i've looking for a solution in the website and saw that the reason is that the usestate is an async awiat which means the variable that i set in the use state isn't immidatly set in it, so i tried many solution that i found in the websites but none of them work for me.
in the screenShot you can see that the json variable is in console log before and the set varaible doesn't show after the setActiveUser , any help?
Thanks!
If you want to do something upon setting state then your best bet is to use the useEffect hook from React and adding your state in the dependency array. This will then call the function in your useEffect every time the state changes. See below a rough example:
import { Text } from 'react-native';
const MyComponent = () => {
const [activeUser, setActiveUser] = useState(null);
useEffect(() => {
// This should log every time activeUser changes
console.log({ activeUser });
}, [activeUser]);
const fetchAuthentication = async user => {
var flag = false;
await fetch('/api/authUser/', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(user),
})
.then(res => {
res.ok && (flag = true);
return res.json();
})
.then(json => {
if (flag) {
setActiveUser(json);
}
})
.catch(error => console.error(error));
return flag;
};
return <Text>Hi</Text>;
};
Full documentation: https://reactjs.org/docs/hooks-effect.html

React-native useEffect hook refresh fetch

I'm trying to build a react-native weather app, fetching data from the openweather api using hooks like this:
useEffect(() => {
async function fetchWeather() {
try {
let data = await fetch(URL);
const json = await data.json();
dispatch({type: 'success', payload: json});
} catch (error) {
dispatch({type: 'failure'});
}
}
fetchWeather();
}, []);
This only loads the data once. I want to make sure the weather info stays up to date. What is the best way to refresh the data? Do I poll every X minutes (if so how)?
Are you looking for a period of time, you will call api?
try it:
const [isStatus, setStatus] = useState(true)
setInterval(()=> {
setStatus(!isStatus)
}, 3000)
useEffect(() => {
fetchWeather();
}, [isStatus])
or you only can use this function:
useEffect(() => {
let loop = setInterval(()=> {
fetchWeather();
}, 3000);
return () => clearInterval(loop);
}, [])
My example applies when the application is opening

Get item from AsyncStorage in React Native

I have a list of companies in React Native.
When I click on one of those companies I get the url of the API that is used for selected company. Then I store it to AsyncStorage and then I show the login screen. The function is as follows:
selectCompany(data_url, e) {
AsyncStorage.setItem("data_url", JSON.stringify(data_url), () => this.props.login());
}
Then on login page if I click on sign in button I go to the onLogin function, the function is as follows:
onLogin: function() {
fetch(data.url + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
},
And data.url comes from data.js file, and I try to get url from the data.js file as follows:
let data_url = AsyncStorage.getItem("data_url").then(json => JSON.parse(json));
module.exports = {
url: data_url,
.....
}
But it doesn't work. Any advice?
AsyncStorage is async, therefore data_url will not be defined until it's retrieved what its looking for, you would need to move the fetch into the promise thats returned from the get so it will run it once it's done getting the data. This might be one way you tackle it:
const data_url = () => AsyncStorage.getItem("data_url"); //change this into a function
module.exports = {
url: data_url,
.....
}
now inside your component...
onLogin: function() {
data.url().then((url) => {
fetch(JSON.parse(url) + '/manager/api/v1/obtain-auth-token/', })
.then(function(body) {
return body.json();
}).then(function(json) {
.....
}).catch(function() {
....
});
});
},
AsyncStorage.getItem is a promise and needs to await for response rather than accessing direct and the function calling it should be defined as async. Here is an example to retrieve from AsyncStorage..
export async function getAccessKey(){
let accessToken = await AsyncStorage.getItem(ACCESS_TOKEN);
return accessToken;
}

React Native - How to see what's stored in AsyncStorage?

I save some items to AsyncStorage in React Native and I am using chrome debugger and iOS simulator.
Without react native, using regular web development localStorage, I was able to see the stored localStorage items under Chrome Debugger > Resources > Local Storage
Any idea how can I view the React Native AsyncStorage stored items?
React Native Debugger has this built in.
Just call showAsyncStorageContentInDev() in the RND console and you'll be able to see a dump of your app's storage.
You can use reactotron i think it has Async Storage explorer ;)
https://github.com/infinitered/reactotron
Following should work,
AsyncStorage.getAllKeys((err, keys) => {
AsyncStorage.multiGet(keys, (error, stores) => {
stores.map((result, i, store) => {
console.log({ [store[i][0]]: store[i][1] });
return true;
});
});
});
I have created a helper method to log all Storage in a single object (more clean to log for example in Reactotron):
import AsyncStorage from '#react-native-community/async-storage';
export function logCurrentStorage() {
AsyncStorage.getAllKeys().then((keyArray) => {
AsyncStorage.multiGet(keyArray).then((keyValArray) => {
let myStorage: any = {};
for (let keyVal of keyValArray) {
myStorage[keyVal[0]] = keyVal[1]
}
console.log('CURRENT STORAGE: ', myStorage);
})
});
}
react native debugger
right click on free space
With bluebird you can do this:
const dumpRaw = () => {
return AsyncStorage.getAllKeys().then(keys => {
return Promise.reduce(keys, (result, key) => {
return AsyncStorage.getItem(key).then(value => {
result[key] = value;
return result;
});
}, {});
});
};
dumpRaw().then(data => console.log(data));
Maybe late, but none of these solutions fit for me.
On android, with Android Studio open file explorer then go to data/data/your_package_name
Inside you should have a folder called database and inside a file RKStorage.
This file is a SQLite3 file so get your favorite SQLite explorer and explore. If you want one this one does the job : DB Browser for SQLite
I did not find Reactotron to have any type of pretty printing enabled and it's also brutally latent so I just wrote a simple function using lodash. You could use underscore too.
Assuming you have a static mapping of all your keys...
const keys = {
key1: 'key1',
key2: 'key2'
}
export function printLocalStorage() {
_.forEach(keys, (k, v) => {
localStore.getAllDataForKey(v).then(tree => {
console.log(k) // Logs key above the object
console.log(tree) // Logs a pretty printed JSON object
})
})
}
It's not performant but it solves the problem.
You can Define function to get all keys by using async and await
getAllkeys = () => {
return new Promise( async (resolve, reject) => {
try {
let keys = await AsyncStorage.getAllKeys();
let items = await AsyncStorage.multiGet(keys)
resolve(items)
} catch (error) {
reject(new Error('Error getting items from AsyncStorage: ' + error.message))
}
});
}
somefunc = async () => {
try {
var items = await getAllkeys();
var someItems = items.filter(function (result, i, item) {
// do filtering stuff
return item;
});
// do something with filtered items
} catch (error) {
// do something with your error
}
}
I have a expo snack that shows this and also performs a "load". So it is useful for doing a dump of the contents and storing it to a file and loading it up later.
Here are they parts.
const keys = await AsyncStorage.getAllKeys();
const stores = await AsyncStorage.multiGet(keys);
const data = stores.reduce(
(acc, row) => ({ ...acc, [row[0]]: row[1] }),
{}
);
// data now contains a JSONable Javascript object that contains all the data
This ammends the data in the AsyncStorage from a JSON string.
// sample is a JSON string
const data = JSON.parse(sample);
const keyValuePairs = Object.entries(data)
.map(([key, value]) => [key, value])
.reduce((acc, row) => [...acc, row], []);
await AsyncStorage.multiSet(keyValuePairs);
import AsyncStorage from "#react-native-async-storage/async-storage";
export const printAsyncStorage = () => {
AsyncStorage.getAllKeys((err, keys) => {
AsyncStorage.multiGet(keys, (error, stores) => {
let asyncStorage = {}
stores.map((result, i, store) => {
asyncStorage[store[i][0]] = store[i][1]
});
console.table(asyncStorage)
});
});
};
enter image description here