React 全栈练习第 5 部分 async/await HTTP 请求的语法和承诺

React fullstack exercise part5 async/await syntax and promises for the HTTP request

我正在赫尔辛基大学学习 React with Fullstack。在其中一个练习中,我需要构建一个前端应用程序并将其与之前构建的后端服务器连接。

我需要实现一个 login/logout 函数。

问题出在我的 HandleLogin 部分。出于某种原因,如果我直接在前端 app.js 中对 axios HTTP 请求使用 promises。连接服务器没有问题。但是,如果我为登录功能创建一个新组件来处理登录按钮。我无法从服务器收到任何东西。我在 HandleLogin 中尝试了 console.log(user),它显示用户 axio/http 而不是 async/await.

谁能向我解释为什么会这样?非常感谢!

我的代码在这里。

App.js

import blogService from './services/blogs'
import loginService from './services/login'
import Blog from './components/Blog'
import LoginForm from './components/LoginForm'
import BlogForm from './components/BlogForm'
import Togglable from './components/Togglable'
import Notification from './components/Notification'
import axios from 'axios'

const App = () => {
  const [blogs, setBlogs] = useState([])
  const [username, setUsername] = useState('') 
  const [password, setPassword] = useState('') 
  const [user, setUser] = useState(null)
  const [loginVisible, setLoginVisible] = useState(false)
  const [Notification, setNotification] = useState("")
  const [Toggle, setToggle] = useState(false)


  useEffect(() => {
    const Data = async () => {
      const initialBlogs = await blogService.getAll()
      setBlogs( initialBlogs )
    }
    Data()
  }, [])

  useEffect(() => {
    const loggedUserJSON = window.localStorage.getItem('loggedBlogAppUser')
    if (loggedUserJSON) {
      const user = JSON.parse(loggedUserJSON)
      setUser(user)
      blogService.setToken(user.token)
    }
  }, [])

  const addBlog = async (blogObject) => {
    BlogFormRef.current.toggleVisibility()
    if (blogObject.title !== '' && blogObject.author !== '' && blogObject.url !== '') {
      const newBlog =  await blogService.create(blogObject)
      setBlogs(blogs.concat(newBlog))
      setNotification(`A new blog ${blogObject.title} by ${blogObject.author} is added`)
      setToggle(!Toggle)
      setTimeout(() => {
        setToggle(false)
      }, 5000)
    } else {
      setNotification('You must fill all fields to create a blog')
      setToggle(!Toggle)
      setTimeout(() => {
        setToggle(false)
      }, 5000)
  }
}

  const BlogFormRef = useRef()

  const blogUpdate = async (blogId, blogObject) => {
    await blogService.update(blogId, blogObject)
    const updatedBlog = {...blogObject, blogId}

    setBlogs(blogs.map((blog) => (blog.id === updatedBlog.id ? updatedBlog : blog)))
  }

  const blogRemove = async (blogId) => {
    await blogService.remove(blogId)

    setBlogs(blogs.filter((blog) => blog.id !== blogId))
  }

  const handleLogin = async (event) => {
    event.preventDefault()
    try{
      const user =  await axios.post(`http://localhost:3001/api/login`, {username, password})

      /*const user = await loginService.login({
        username, 
        password
      })*/ //this is not working

      console.log(user)
      console.log(user.data.name)
      window.localStorage.setItem('loggedBlogAppUser', JSON.stringify(user)) 
      blogService.setToken(user.data.token)
      setUser(user)
      setUsername('')
      setPassword('')
      setNotification(`User ${user.data.name} is logged in`)
    } catch (exception) {
      setNotification('Wrong username or password')
      setToggle(!Toggle)
      setTimeout(() => {
        setToggle(false)
      }, 5000)
    }
  }
  //console.log(user)

  const handleLogout = () => {
    window.localStorage.removeItem('loggedBlogAppUser')
    document.location.reload()
  }

  const blogForm = () => (
    <Togglable buttonLabel='new blog' cancelButtonLabel="Cancel" ref={BlogFormRef}>
      <BlogForm createBlog={addBlog} />  
    </Togglable>
  )

  const loginForm = () => {
    const hideWhenVisible = { display: loginVisible ? 'none' : ''}
    const showWhenVisible = { display: loginVisible ? '' : 'none'}

    return(
      <div>
        <div style={hideWhenVisible}>
          <button onClick={() => setLoginVisible(true)}>log in</button>  
        </div>
        <div style={showWhenVisible}>
          <LoginForm
            username={username}
            password={password}
            handleUsernameChange={({target}) => setUsername(target.value)}
            handlePasswordChange={({target}) => setPassword(target.value)}
            handleSubmit={handleLogin}/>
        </div>
      </div>
      
    )
  }

  return (
    <div>
       <h2>Blog11</h2>
      {user && (
        <div>
          {user.data.name} is logged in
        <button onClick={handleLogout}>Logout</button>
      </div>
      )}  
       
      <div>
        {user === null ? loginForm()
        :(
          <>
          {blogForm()}
          <div>
          {blogs.map(blog =>
        <Blog
          key={blog.id}
          blog={blog}
          blogUpdate={blogUpdate}
          blogRemove={blogRemove}/>
        )}
          </div>
          </>
        )
        }
      </div>
    </div>
  )
}

export default App

登录服务

const baseUrl = `/api/login`

const login = async (credentials) => {
    const response = await axios.post(baseUrl, credentials)
    return response.data
}

export default login

第一次在Whosebug上提问。谢谢大家的耐心等待。

我放弃了使用独立模块。相反,我在 App.js 中使用了 await axios.post 并且没有问题。

 try{
  const user =  await axios.post(`http://localhost:3001/api/login`, {username, password})

  /*const user = await loginService.login({
    username, 
    password
  })*/ //this is not working

  //console.log(user)
  //console.log(user.data.name)
  window.localStorage.setItem('loggedBlogAppUser', JSON.stringify(user)) 
  blogService.setToken(user.data.token)
  setUser(user)
  setUsername('')
  setPassword('')
  setNotification(`User ${user.data.name} is logged in`)
} catch (exception) {
  setNotification('Wrong username or password')
  setToggle(!Toggle)
  setTimeout(() => {
    setToggle(false)
  }, 5000)
}

}