React Native Firebase Auth user is null - javascript

I have integrated the #react-native-firebase/auth package for user authentication. On the 'onAuthStateChanged' listener the user object is null without calling the signout. Are there any possible fixes for this?

I resolved same issue. But in React application 🙃
It's happened because u need to wait, before firebase-auth get authenticated user. So, you can create useState with default loading in true position. And while it's loading - display spinner or something else. When user will be load - setLoading to false with useEffect.
My app.js:
const [loading, setLoading] = useState(true);
const [user, setUser] = useState(null);
useEffect(() => {
onAuthStateChanged(auth, (authorizedUser) => {
if (authorizedUser) {
console.log('success sign-in')
setUser(authorizedUser);
setLoading(false);
}
});
}, []);

Related

How to control (useEffect ). HOOK

I am creating a front end for an API in react native. For signed authentication, I use the FireBase service. Everything is good, However, I have a problem. I want after creating the user, my program stays on the login screen and when on the login screen provide the credential, it should move to the Home screen.
In my case, it navigates to the login screen and then use effect () activate and it navigates to the Home. How can I stay in HomeScreen?
// Registrationscreen
const handleSignUp = () => {
createUserWithEmailAndPassword( auth,email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.then( navigation.dispatch(
StackActions.replace('Login', {
user: 'jane',
})
))
.catch((error) => alert(error.message));
};
//logIn Screen
const LoginScreen = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const navigation = useNavigation();
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
if (user) {
navigation.replace("Home");
}
});
return unsubscribe;
}, []);
const handleLogin = () => {
signInWithEmailAndPassword(auth, email, password)
.then((userCredential) => {
// Signed in
const user = userCredential.user;
// ...
})
.catch((error) => alert(error.message));
};
I wanted that after registration of the new user, it should navigate to the login page and Stay there and when we put in the credential and press logIn then it should navigate to the Home Screen.
There's unfortunately a lot of places this could be going wrong but it looks like there's a pretty serious error in your LoginScreen component - the useEffect is only running when the component initially renders. This means that by the time the handleLogin function is called the useEffect doesn't know that it needs to run again - which means the redirect to the home screen never runs.
To temporarily fix this: create a user object in state. When the user gets returned from signInWithEmailAndPassword you can store the user into state. Reminder you'd need to update your dependency array in the useEffect to include the user object.

React doesn't call useEffect on firebase (v9) auth update

I'm uploading a user profile image into firebase storage, then updating the photoURL value of the auth user with updateProfile(). After that I want the user to be updated without manually refreshing the page. I've been trying this for days now and the issue gets more weird every time I try to debug it.
The interesting thing is the user object seems to be already updated when I log it with console.log(currentUser) after the then promise of updateProfile() is fulfilled. So the new photoURL is already present in the currentUser object. But it seems to not call a state update or console.log("!!!!currentAuthUserUpdate", user);. So the user image wouldn't refresh in my page.
I even tried it with doing a useEffect with the currentUser as a dependency but it wasn't fired. Still, the currentUser object changed when logging it after updateProfile()
Updating the profile, UpdateUserImage.tsx:
import { useAuth } from "../../contexts/AuthContext";
const { currentUser } = useAuth();
// updating the user profile
updateProfile(currentUser, { photoURL })
AuthContext.tsx:
import { auth } from "./../firebase/firebase";
const [currentUser, setCurrentUser] = useState(null);
const auth = getAuth(app);
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
console.log("!!!!currentAuthUserUpdate", user);
// I tried setting the user as a custom new object: const userData = { ...user };
setCurrentUser(user);
});
return unsubscribe;
}, []);
firebase.js
import { getAuth } from "firebase/auth";
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
export {
auth
};
What I tried additionally: (But this wouldn't work as the user is already updated without a state refresh from react, so it's trying to replace the same object)
const reloadUser = async () => {
try {
const res = await currentUser.reload();
const user = auth.currentUser;
console.log("currentUser:", user);
setCurrentUser(auth.currentUser);
console.log("res", res);
} catch (err) {
console.log(err);
}
};
it's not auth.onAuthStateChanged. You need to import onAuthStateChanged from 'firebase/auth'
import { getAuth, onAuthStateChanged } from "firebase/auth"
const auth = getAuth(); // leave getAuth empty if you only have one app
Then in your useEffect it should be
onAuthStateChanged(auth, async (currentUser) => { ... }
The setCurrentUser function returned from useState isn't always the same function in my experience.
You can try passing it as a dependency into the useEffect - but I don't think that's what you want.
React lets you use an old useState setter if you give it an updater function, rather than a value: setCurrentUser(()=>auth.currentUser)
The React docs dispute this though.
Using useStates are good for re-rendering components. However going into utilizing useRefs are best for updating the actual variable and will not cause a re-render of the component.
Declare it like:const currentUser = useRef(null)
Update it like: currentUser.current = updatedUserData
Use in code like: currentUser.current.photoURL

UseEffect to update navbar when user is logged in?

I'm working on a navbar that changes whenever it detects there is a user in local storage using useState and useEffect. Here's my logic:
const [user, setUser] = useState("")
function fetchData(){
const item = JSON.parse(localStorage.getItem('name'))
if(item) {
setUser(item)
}
}
useEffect(() => {
fetchData()
});
return({user? (<LoggedIn />) : (<ClientBar />})
The code essentially begins with no user, and in the fetchData() function it checks whether a user exists in local storage and sets the user based on what's been found in local storage. I can tell the logic works because when I refresh it, it changes from <ClientBar> to <LoggedIn>. However, the problem is it doesn't work upon login - rather, it requires a refresh to update. Is there a way to make it update immediately upon login?
Your useEffect should be:
useEffect(() => {
fetchData()
}, [user])
So when user changes it will check each time. Because you're fetching localstorage I'd also encourage you to add a loading component while that's being done.
Checking localstorage Should also be using async/await:
const fetchData = async () => {
const item = await JSON.parse(localStorage.getItem('name'))
if(item) setUser(item)
}
While this it's waiting for the check you should render a loading with another useState.
As Abhi Patil stated, you need to check localStorage changes. It has nothing to do with useEffect as it is only triggered when the component is mounted.
You need to wrap fetchData() inside storage event listener like so:
useEffect(() => {
window.addEventListener('storage', () => {
const item = JSON.parse(localStorage.getItem('name'))
if(item) {
setUser(item)
}
})
})

useEffect hook not working properly while calling onAuthStateChanged

I am able to login a user successfully using Firebase. In my code, after the user has successfully logged in, they are directed to their profile. My problem is that whenever I refresh the browser, the user is logged out for a split second and then directed back to their profile. If I'm on any other page, the user is completely logged out. I'm quite new to custom hooks and am trying to learn on the job. Here's my code
const [currentUser, setCurrentUser] = useState("")
const [currentUserData, setCurrentUserData] = useState("")
const [loading, setLoading] = useState(false)
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged(user => {
if (user) {
setCurrentUser(user)
db.collection('users')
.doc(user.uid)
.get()
.then(doc => {
setCurrentUserData(doc.data())
// MUST REARANGE vvvv
history.push('/')
})
setLoading(false)
}
else {
setCurrentUser(null)
setCurrentUserData(null)
}
})
return unsubscribe
}, [history])

trying to get config from backend to react front-end

Am trying to make a script that easy to edit for users from the back-end, so they won't need to re-build the react app each time they edit something (such as color, phone number etc)
so i make a call to the back-end by axios
let config={};
(async () => {
try {
config = await axios.get("http://localhost:8000/settings");
config = config.data;
} catch (e) {
alert(e);
}
})();
const App = () => {
let show;
///
const [name, setName] = useState("");
const [inchat, setInchat] = useState(false);
const { t, i18n } = useTranslation();
///settings
const [direction, setDirection] = useState("text-left");
const [socket] = useState(openSocket(config.url || '/'));
console.log(socket)
const [settings] = useState(config);
as you see, after loading the config file from back-end, am using it here in front-end.
the problem is that sometimes the App component load first, and the script throw error of config undefind, how can i make the script http request lunch first, i tried to put the http request inside a useEffect hook but still the same problem.
thank you
This is how I usually implement things when it comes to http requests.
This is assuming that you're not using Server Side Rendered (SSR) service like Next.js, where you want the data to be fetched before the page is even rendered, then you would use a different approach.
Otherwise you could show a loading animation or just show a blank screen until the data is loaded.
Click the "Run code snippet" button below to see it work.
// main.js
const { useState, useEffect } = React;
const App = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
const [data, setData] = useState(null);
useEffect(() => {
/*
StackOverflow not letting me do async/await so doing a promise
*/
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => response.json())
.then(json => {
setData(json);
setLoading(false);
})
.catch(error => {
console.log('ERROR', error);
setError(error);
setLoading(false);
});
}, []);
return <div>
{loading
? <p>Loading...</p>
: <div>
{error
? <div>{JSON.stringify(error)}</div>
: <div>Loaded <br />{JSON.stringify(data)}</div>
}
</div>}
</div>
}
ReactDOM.render(<App />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Since the call to your API is async you will need to wait for the call to be finished to show your app, useEffect is a good way to do it, but you will need to make some changes in your code to work.
I see that you are handling all the state variables separately but some of them depend on each other, for this cases is better to use an object so you can be sure all the properties are updated at the same time and also to know if you have already the needed data to show your app
// show your app until this is not null
const [state, setState] = useState(null);
// set all the state variables at the same time
useEffect(() => { axios.get(url).then(config => setState(config)) })
if(!state) return <div>Loading...</>
return <div>App</div>
Another alternative is to use another state variable to control if you should show your app or not
// all your state variables
const [state, setState] = useState(null);
.
.
const [isLoading, setIsLoading] = useState(false);
// set all the state variables at the same time
useEffect(() => {
setLIsLoading(true);
axios.get(url).then(config => {
setIsLoading(false);
setState(config);
)
})
if(isLoading) return <div>Loading...</>
return <div>App</div>

Categories