코인잼

코인잼 리팩토링 하기 -2부-

잼굴 2023. 2. 15. 15:48

 

리덕스툴킷!!

리덕스 툴킷을 사용하고자, 기존 기능들을 리팩토링 하였다.

 

npm install @reduxjs/toolkit

 

우선 툴킷을 설치했다.

 

import React from 'react'
import ReactDOM from 'react-dom/client'
import './index.css'
import App from './App'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import ConfigureStore from './store/configureStore'

const root = ReactDOM.createRoot(document.getElementById('root'))
root.render(
  <BrowserRouter>
    <Provider store={ConfigureStore}>
      <App />
    </Provider>
  </BrowserRouter>
)

index.js에서 App을 Provider로 감싸고 store를 연결했다.

 

import { createSlice } from '@reduxjs/toolkit'

const authSlice = createSlice({
  name: 'auth',
  initialState: {
    user: null,
  },
  reducers: {
    login: (state, action) => {
      state.user = action.payload
    },
    logout: (state) => {
      state.user = null
    },
  },
})
export const selectUser = (state) => state.auth.user
export const { login, logout } = authSlice.actions
export default authSlice.reducer

코드 설명: 리덕스 툴킷을 사용하여 스토어에서 사용할 수 있는 authSlice를 생성하는 코드이다.

 

먼저, createSlice() 함수를 사용하여 auth slice를 생성한다.

이 authSlice함수는 name, initialState, reducers를 인수로 받는다.

name은 slice의 이름, initialState는 slice의 초기 상태를 정의한다

initialState에서 user를 null로 설정해뒀는데, 초기 상태에는 사용자가 로그인 하지않았기 때문이다.

 

reducers는 slice에 적용할 수 있는 액션을 정의한다.

login 액션은 state 객체와 action 객체를 인수로 받으며, state.user 값을 action.payload로 업데이트한다.

logout 액션은 state.user 값을 null로 업데이트한다.

 

그런 다음, selectUser 함수는 state 객체를 인수로 받고, state.auth.user를 반환한다.

이 함수는 Redux 스토어에서 현재 사용자 객체를 선택하는 데 사용된다.

마지막으로, authSlice.actions에서 login과 logout 액션을 export하고, authSlice.reducer를 exoport default로 내보낸다.

이렇게 하면 slice의 액션 및 리듀서가 외부에서 사용 가능해진다.

 

 

import { configureStore } from '@reduxjs/toolkit'
import authReducer from './authStore'

const store = configureStore({
  reducer: {
    auth: authReducer,
  },
})

export default store

이제 만든 리듀서를 툴킷의 configureStore를 통해서 store로 사용할수있게 해준다.

 

큰 뼈대 설정은 끝났다.

 

PS) 툴킷의 configureStore << 얘는 많은걸 지원해준다.

이번에 사용한 reducer를 포함하여 middleware, devTools, preloadState, enhancers, middlewareThunkExtraArgument, reducerPath등 다양한 큼지막한 기등들이 있다.  

 


2. 적용하기

 

useSelector와 dispatch, selectUser를 사용하여 유저정보들을 리덕스 Store에서 가져오도록 변경하였다.

 

 

 

import Navbar from './components/template/Navbar'
import React, { useEffect, useState } from 'react'
import { ThemeProvider } from './context/ThemeContext'
import { Route, Routes } from 'react-router-dom'
import Home from './pages/Home'
import Signin from './pages/Signin'
import Signup from './pages/Signup'
import Account from './pages/Account'
import Coinpage from './pages/Coinpage'
import Footer from './components/template/Footer'
import { getCoins } from './queries/getCoins'
import { useDispatch } from 'react-redux'
import { login, logout } from './store/authStore'
import { onAuthStateChanged } from 'firebase/auth'
import { auth } from './firebase'

function App() {
  const dispatch = useDispatch()
  const [coins, setCoins] = useState([])

  // page load 때 user 체크
  useEffect(() => {
    onAuthStateChanged(auth, (userAuth) => {
      if (userAuth) {
        // 유저가 존재하면 login dispatch
        dispatch(
          login({
            email: userAuth.email,
            uid: userAuth.uid,
          })
        )
      } else {
        dispatch(logout())
      }
    })
  }, [])

  useEffect(() => {
    getCoins()
      .then((response) => {
        setCoins(response.data)
        console.log(response.data)
      })
      .catch(() => {
        alert('코인게코의 서버가 불안정합니다.')
      })
  }, [])

  return (
    <ThemeProvider>
      <Navbar />
      <Routes>
        <Route path="/" element={<Home coins={coins} />} />
        <Route path="/signin" element={<Signin />} />
        <Route path="/signup" element={<Signup />} />
        <Route path="/account" element={<Account />} />
        <Route path="/coin/:coinId" element={<Coinpage />}>
          <Route path=":coinId" />
        </Route>
      </Routes>
      <Footer />
    </ThemeProvider>
  )
}
export default App

onAuthStateChanged 함수를 사용하여 유저의 로그인 상태를 확인하는 하게하였다.

이를통해 사용자가 로그인한 상태에서 앱을 종료하고, 다시 열었을 때, 사용자가 다시 로그인해야하는 번거로움을 없앨 수 있다.

onAuthStateChanged 함수를 사용하여 이전 로그인 정보를 확인하고, 이 정보를 이용하여 Redux 스토어와 같은 앱의 상태를 초기화할 수 있다.

또한 리덕스 툴킷을 적용 활용하였다.

 

import React, { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import EmailInput from '../components/molecules/EmailInput'
import PasswordInput from '../components/molecules/PasswordInput'
import { createUserWithEmailAndPassword } from 'firebase/auth'
import { auth, db } from '../firebase'
import { useDispatch } from 'react-redux'
import { login } from '../store/authStore'
import { doc, setDoc } from 'firebase/firestore'

const Signup = () => {
  const dispatch = useDispatch()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [error, setError] = useState('')
  const navigate = useNavigate()
  const handleSubmit = async (e) => {
    e.preventDefault()
    setError('')
    createUserWithEmailAndPassword(auth, email, password)
      .then((userAuth) => {
        setDoc(doc(db, 'users', email), {
          watchList: [],
        })
        dispatch(
          login({
            email: userAuth.user.email,
            uid: userAuth.user.uid,
          })
        )
        navigate('/')
      })
      .catch((err) => {
        alert(err)
      })
  }
import React, { useState } from 'react'
import { Link, useNavigate } from 'react-router-dom'
import EmailInput from '../components/molecules/EmailInput'
import PasswordInput from '../components/molecules/PasswordInput'
import { useDispatch } from 'react-redux'
import { signInWithEmailAndPassword } from 'firebase/auth'
import { auth } from '../firebase'
import { login } from '../store/authStore'

const Signin = () => {
  const dispatch = useDispatch()
  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')
  const [error, setError] = useState('')
  const navigate = useNavigate()
  const handleSubmit = async (e) => {
    e.preventDefault()
    setError('')
    signInWithEmailAndPassword(auth, email, password)
      .then((userAuth) => {
        dispatch(
          login({
            email: userAuth.user.email,
            uid: userAuth.user.uid,
          })
        )
        navigate('/account')
      })
      .catch((err) => {
        setError(err.message)
        alert(err)
      })
  }
import React from 'react'
import { Navigate, useNavigate } from 'react-router-dom'
import SavedCoin from '../components/template/SavedCoin'
import { useDispatch, useSelector } from 'react-redux'
import { logout, selectUser } from '../store/authStore'
import { auth } from '../firebase'

const Account = () => {
  const user = useSelector(selectUser)
  const dispatch = useDispatch()
  const navigate = useNavigate()
  const handleSignOut = async () => {
    dispatch(logout())
    await auth.signOut()
    navigate('/')
  }

회원가입, 로그인, 계정페이지에도 리덕스를 적용하였다.

 

'코인잼' 카테고리의 다른 글

코인잼 업데이트 하기 -1부-  (0) 2023.02.20
코인잼 리팩토링 하기 -3부-  (0) 2023.02.17
코인잼 리팩토링 하기 -1부-  (1) 2023.02.13