FullStackOpen Part5-a Login in frontend メモ


Handling login

ログイン機能を付けたフロントエンド側のApp.jsはこんな感じ

const App = () => {
  const [notes, setNotes] = useState([]) 
  const [newNote, setNewNote] = useState('')
  const [showAll, setShowAll] = useState(true)
  const [errorMessage, setErrorMessage] = useState(null)
  const [username, setUsername] = useState('') 
  const [password, setPassword] = useState('') 

  useEffect(() => {
    noteService
      .getAll().then(initialNotes => {
        setNotes(initialNotes)
      })
  }, [])

  // ...

  const handleLogin = (event) => {
    event.preventDefault()
    console.log('logging in with', username, password)
  }

  return (
    <div>
      <h1>Notes</h1>

      <Notification message={errorMessage} />

      <form onSubmit={handleLogin}>
        <div>
          username
            <input
            type="text"
            value={username}
            name="Username"
            onChange={({ target }) => setUsername(target.value)}
          />
        </div>
        <div>
          password
            <input
            type="password"
            value={password}
            name="Password"
            onChange={({ target }) => setPassword(target.value)}
          />
        </div>
        <button type="submit">login</button>
      </form>

      // ...
    </div>
  )
}

export default App

<input>中のonChangeは関数自体を引数にとるので以下のようになる
eventオブジェクトからtargetを{}で直接取り出し、setUsernameにtarget.valueを収めている

onChange={({target}) => setUsername(target.value)}

以下のような感じでログイン済みかどうかでレンダリングする対象を変更

    {user === null ?
      loginForm() :
      noteForm()
    }

Creating new notes

ログインして取得したトークンを使用してノートを投稿できるようにする

import axios from 'axios'
const baseUrl = '/api/notes'

let token = null
const setToken = newToken => {  token = `Bearer ${newToken}`}
const getAll = () => {
  const request = axios.get(baseUrl)
  return request.then(response => response.data)
}

const create = async newObject => {
  const config = {    headers: { Authorization: token },  }
  const response = await axios.post(baseUrl, newObject, config)  return response.data
}

const update = (id, newObject) => {
  const request = axios.put(`${ baseUrl }/${id}`, newObject)
  return request.then(response => response.data)
}

// eslint-disable-next-line import/no-anonymous-default-export
export default { getAll, create, update, setToken }

Saving the token to the browser's local storage

トークンをブラウザのストレージに保存しておくにはwindow.localStorageを使用する
W12のコンソールからもwindow.localStorageで見れる
以下使用例:

window.localStorage.setItem('name', 'juha tauriainen')
window.localStorage.getItem('name')
window.localStorage.removeItem('name')

オリジンごとにストレージは設定されている

ログインを変更すると以下のような感じに

  const handleLogin = async (event) => {
    event.preventDefault()
    try {
      const user = await loginService.login({
        username, password,
      })

      window.localStorage.setItem('loggedNoteappUser', JSON.stringify(user))
      noteService.setToken(user.token)
      setUser(user)
      setUsername('')
      setPassword('')
    } catch (exception) {
      // ...
    }
  }

このままだとブラウザを更新するたびにログインしないといけないため、useEffectを使用し、コンポーネントが初回にレンダーされるときにlocalStrogeを確認するように設定

const App = () => {
  const [notes, setNotes] = useState([]) 
  const [newNote, setNewNote] = useState('')
  const [showAll, setShowAll] = useState(true)
  const [errorMessage, setErrorMessage] = useState(null)
  const [username, setUsername] = useState('') 
  const [password, setPassword] = useState('') 
  const [user, setUser] = useState(null) 

  useEffect(() => {
    noteService
      .getAll().then(initialNotes => {
        setNotes(initialNotes)
      })
  }, [])
  
 useEffect(() => {
    const loggedUserJason = window.localStorage.getItem('loggedNoteappUser')
    if (loggedUserJason) {
      const user = JSON.parse(loggedUserJason)
      setUser(user)
      noteService.setToken(user.token)
    }
  }, [])
//....
 

いいなと思ったら応援しよう!