Warning: Can't perform a React state update on an unmounted component
raelb opened this issue · comments
Hi Kyle, Thanks for the super tutorial.
I just wanted to point out, when you move from the login page to the dashboard, the console shows a warning:
It looks like the problem is caused (in Login.js) by setting state after call to history.push
which already moves to the Dashboard component.
async function handleSubmit(e) {
e.preventDefault()
try {
setError('')
setLoading(true)
await login(emailRef.current.value, passwordRef.current.value)
history.push('/')
} catch {
setError('Failed to sign in')
}
setLoading(false) // --> problem
}
Is the correct solution to just remove call to setLoading
, or is there a better solution?
Hi @raelb ! I was stuck in the same problem and after some research I understand that the setLoading
was called after the history.push
, and as I understand, when you call history.push
you unmount the component (in this case Login
) but the function handleSubmit
have to terminate and it executes setLoading
on something that doesn't exists anymore.
I edited the code like this, and it works:
async function handleSubmit(e){
e.preventDefault()
try {
setError('')
setLoading(true)
await login(emailRef.current.value, passwordRef.current.value)
setLoading(false)
history.push('/home')
} catch {
setLoading(false)
setError('Failed to login')
}
}
This answer enlighted me, but I'd like to know if my conclusions are right :)
I had the same problem, but my issue was that I was using the de-structuring curly braces when setting history
from useHistory()
in Dashboard.js. That was causing history
to be undefined
.
It's an easy mistake given that so many hooks require de-structured assignment syntax. e.g.
React-Firebase-Auth/src/components/Dashboard.js
Lines 7 to 9 in c355408
I'm getting same error while using REST API Login. How can I use useEffect function while working with API.
`export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState()
const [loading, setLoading] = useState(false)
async function signup(email, password) {
console.log("Signup");
}
async function login(email, password) {
try {
const resp = await axios.post('http://localhost:8080/api/login', {
email, password
})
console.log(resp.data);
setCurrentUser(resp.data.token)
} catch (error) {
console.log(error);
}
}
function logout() {
console.log("Logout");
// return auth.signOut()
}
const value = {
login,
signup,
logout,
currentUser
}
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
)
}`
@dhruvangg I would try moving the async login handling to Login.js. Only return the axios.post
promise to login()
. Then handle the async/await in the handleSubmit()
function in Login.js.
The problem with that is that you will need a way to setCurrentUser
from Login.js. To do that I would export setCurrentUser
in AuthContext.js (in the value attribute like the rest). Then import it in Login.js from useAuth
along with the login
function so you can use it in handleSubmit()
.
In other words, you probably don't need useEffect
for axios.post
. The reason it was used for auth.onAuthStateChanged
was so that the listener can be unsubscribed when the component is destroyed. axios.post
doesn't set a listener. It just returns a promise.
I suppose you could useEffect in Login.js and set it's dependency to currentUser
, but I'm new to React hooks myself and haven't played with it that much yet. Just some thoughts.
Good progress. Keep up the good work.