Reputation: 770
I am new to React Native. In my app, the same function to check if user exists in the database is used in 3 different files.
checkUserExists = (userId) => {
var that = this;
database.ref('users').child(userId).once('value').then(function(result){
const exists = (result.val() !== null);
if (exists) {
var data = result.val();
that.setState({
username: data.username,
name: data.name
})
}
})
}
To reduce amount of code, I want to put this function into a component so that it can be reused. So I created a new file with this function:
export function checkUserExists (userId) {
database.ref('users').child(userId).once('value').then(function(result){
const exists = (result.val() !== null);
if (exists) {
var data = result.val();
setState({
username: data.username,
name: data.name
})
}
})
}
But this is met with [Unhandled promise rejection: ReferenceError: Can't find variable: setState]
What is the proper way to handle this? Do I have to use Redux? I can't find a clear answer on SO so far.
Update: I also tried
export default class Authentication extends Component {
checkUserExists = (userId) => {
database.ref('users').child(userId).once('value').then(function(result){
const exists = (result.val() !== null);
if (exists) {
var data = result.val();
setState({
username: data.username,
name: data.name
})
}
})
}
}
and I tried to call it like
Authentication.checkUserExists(user.id);
but gets: TypeError: _authentication.default.checkUserExists is not a function
Upvotes: 3
Views: 578
Reputation: 6088
You need to call this.setState
from within a component. You can't just call if from anywhere.
Your helper function is not bound to your class. Notice in the original var that = this
is set up so that that.setState
will work from within the then
block. It's likely that checkUserExists
is bound using https://github.com/tc39/proposal-class-fields in your original example. Now you've got a regular (not bound to the class) function and it has no access to this
nor any of its methods, including setState
.
To be honest though, this is an XY problem, imho. If you want to extract a helper function, you should have it return the data you need, not attempt to pass around references to the class whose state you want to update. You should instead just return the data to the component --and you have to do this because your database call is async anyway-- and use that data within the component to call its own setState
method.
https://reactjs.org/docs/react-component.html#setstate
Upvotes: 0
Reputation: 281874
Two things you can do to make it work
checkUserExists
function where you execute it with the class context export function checkUserExists (userId) {
database.ref('users').child(userId).once('value').then((result) => {
const exists = (result.val() !== null);
if (exists) {
var data = result.val();
this.setState({
username: data.username,
name: data.name
})
}
})
}
Now where you wanna use checkUserExists, you would use it with .call like
checkUserExists.call(this, userId);
One downside of this solution though is that it might be difficult to debug your app as the state is being set from code that is outside of the component
To overcome the downside you can define your method like
export async function checkUserExists (userId) {
try {
const result = await database.ref('users').child(userId).once('value');
const exists = (result.val() !== null);
if (exists) {
return data;
}
return false;
} catch(e) {
console.log(e);
}
}
and in the component use it like
someFunc = async () => {
const data = await checkUserExists(userId);
if (data) {
this.setState({
username: data.username,
name: data.name
})
}
}
Upvotes: 1