You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React异步登录请求完成前阻止组件render调用的方案问询

Hey there, let's break down what's happening here and fix it step by step.

The core issue is that your handleLogin function makes an asynchronous axios call, but you're not waiting for it to complete before your component re-renders. Right now, when you call handleLogin(this.state) in handleSubmit, it fires off the POST request and immediately returns—so your component's render method runs right away, before localStorage gets updated, hence isLoggedIn() still returns false.

Here's how to fix this:

1. Make handleLogin return a Promise

First, update your handleLogin function in /utils/auth.js to return the axios promise chain. This lets you wait for the login request to finish in your component:

// in /utils/auth.js
import axios from 'axios'

const isBrowser = typeof window !== `undefined`
const getUser = () => window.localStorage.gatsbyUser ? JSON.parse(window.localStorage.gatsbyUser) : {}
const setUser = user => (window.localStorage.gatsbyUser = JSON.stringify(user))

export const handleLogin = ({ email, password }) => {
  if (!isBrowser) return Promise.resolve(false);
  
  return axios.post(`${process.env.API_URL}/sessions`, { email, password })
    .then(response => {
      console.log(response);
      setUser({
        name: `Jim`,
        legalName: `James K. User`,
        email: email,
      });
      return true; // Indicate login success
    })
    .catch(error => {
      console.error('Login failed:', error);
      return false; // Indicate login failure
    });
};

export const isLoggedIn = () => {
  if (!isBrowser) return false
  const user = getUser()
  return !!user.email
}

2. Add a loading state to your Login component

Add a isLoggingIn state variable to track when the login request is in progress. This lets you block the form from re-rendering prematurely and show a loading state to the user:

import React from "react"
import { Redirect } from "react-router-dom"
import axios from 'axios'
import Form from "./Form"
import View from "./View"
import { handleLogin, isLoggedIn } from "../utils/auth"

export default class Login extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      email: ``,
      password: ``,
      isLoggingIn: false, // New loading state
    };
  }

  handleUpdate(event) {
    this.setState({ 
      [event.target.name]: event.target.value,
    })
  }

  async handleSubmit(event) {
    event.preventDefault();
    // Mark login as in progress
    this.setState({ isLoggingIn: true });
    
    // Wait for the login request to complete
    const loginSuccessful = await handleLogin(this.state);
    
    // Mark login as finished
    this.setState({ isLoggingIn: false });
    
    // Optional: Handle failure case (e.g., show error message)
    if (!loginSuccessful) {
      // Add code here to show an error to the user
      console.log('Login failed!');
    }
  }

  render() {
    // Redirect if already logged in
    if (isLoggedIn()) {
      return <Redirect to={{ pathname: `/app/profile` }} />
    }

    // Show loading state while login is in progress
    if (this.state.isLoggingIn) {
      return (
        <View title="Log In">
          <div>Logging in, please wait...</div>
        </View>
      );
    }

    // Render the login form normally
    return (
      <View title="Log In">
        <Form 
          handleUpdate={e => this.handleUpdate(e)} 
          handleSubmit={e => this.handleSubmit(e)} 
        />
      </View>
    )
  }
}

Why this works:

  • By making handleLogin return a Promise, we can use async/await in handleSubmit to wait for the axios request to finish before updating the component state.
  • The isLoggingIn state ensures that while the login request is pending, we show a loading state instead of the form, preventing any premature re-renders that would check isLoggedIn() before localStorage is updated.
  • Once the request completes and setUser updates localStorage, the next re-render (triggered by setState({ isLoggingIn: false })) will detect that isLoggedIn() returns true and trigger the Redirect.

Bonus: Consider moving user state to component state (optional)

If you want to avoid relying on localStorage for immediate state checks, you could also track the user directly in your component's state (or use a global state manager like Context API or Redux). This would make state updates more synchronous and avoid any edge cases with localStorage. But the above solution is the most straightforward fix for your current setup.

内容的提问来源于stack exchange,提问作者Matt

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:07:35