Redux - Redux 총 정리

일상 코딩·2022년 10월 7일
1

Redux

목록 보기
6/6

01.Redux란?

  • Redux는 여러 컴포넌트 또는 전체 컴포넌트들의 데이터 상태(state)를 관리하는 상태 관리 라이브러리 입니다.

02.Redux를 사용하는 이유

  • props 문법이 귀찮을 때 사용합니다.
  • React에서는 하위 컴포넌트가 부모 컴포넌트의 변수값을 사용할려면 반드시 부모 컴포넌트에서 하위 컴포넌트로 사용할 변수를 props형태로 넘겨줘야 합니다.
  • 만약 하위 컴포넌트가 1개가 아니라 여러개일 경우 Redux를 사용하면 하위 컴포넌트들에서 쉽게 부모 컴포넌트의 변수를 사용할 수 있습니다.
  • state 변경 관리할 때 사용합니다.
  • Redux를 설치하면 state를 보관할 수 있는 파일을 만들수 있습니다. (ex> store.js)
  • 모든 컴포넌트들이 props없이도 store.js에 있는 변수들을 참조하여 사용할 수 있습니다.

03.Redux 구현

Redux 설치

  • npm install react-redux
  • npm install redux

Redux 기본 셋팅

  • Store.js
import { Provider, useDispatch, useSelector } from "react-redux"
import { createStore } from "redux"

const 체중 = 100; // state 맘대로 보관 가능

function reducer(state = 체중, action) {
	return state;
}

let store = createStore(reducer)

	ReactDOM.render(
	<Provider store={store}>
	<App />
	</Provider>
)
  • Component에서 Store에 있던 state사용 방법
import { useSelector, useDispatch } from "react-redux"

function() App() {
	const 꺼내온값 = useSelector((state) => state);
   
    return (
    <div>
    <p>님의 처참한 몸무게: {꺼내온값}</p>
    </div>
    );

export default App;
}

실행 결과

  • store.js에 저장되어 있던 값 100이 꺼내온값을 통해 화면에 출력됩니다.
  • 이처럼 Redux를 사용하면 모든 Componentprops 없이도 state를 직접 꺼내어 사용할 수 있으며 이것이 바로 Redux를 사용하는 첫번째 이유라고 할 수 있습니다.
  • Store.js에서 상태 관리 방법 (Reducer)
  • state값의 수정방법들을 Store.js에 있는 Reducer에 정의합니다.
  • 각각의 Component에서는 상태값 변경을 하기위해 Store.js에 정의된 Reducer에 수정 요청을 보내야 합니다. (dispatch 이용)
import { Provider, useDispatch, useSelector } from "react-redux"
import { createStore } from "redux"

const 체중 = 100; // state 맘대로 보관 가능

function reducer(state = 체중, action) {
  if(action.type === "증가") return state++;
  else if(action.type === "감소") return state--;
  else return stats;
}

let store = createStore(reducer)

	ReactDOM.render(
	<Provider store={store}>
	<App />
	</Provider>
)

Component에서 state값을 수정 요청하는 방법 (dispatch)

import { useSelector, useDispatch } from "react-redux"

function() App() {
	const 꺼내온값 = useSelector((state) => state);
  	const dispatch = useDispatch()
   
    return (
    <div>
    <p>님의 처참한 몸무게: {꺼내온값}</p>
	<button onClick={() => {dispatch({type: "증가"}) }}>더하기</button>
    </div>
    );

export default App;
}

실행 결과

  • 더하기 버튼을 클릭하면 Componentdispatch함수의 type값에 알맞은 값을 Store.js에 수정 요청을 보내면 Store.js에서 reducer에 정의된 조건에 따라 상태 값을 변경 시킵니다.
  • 이처럼 Redux를 사용하면 Store에 있던 상태(state)값을 변경 및 관리할 수 있으며 이것이 바로 Redux를 사용하는 두번째 이유라고 할 수 있습니다.

03.참고한 영상


04.직접 Redux를 사용하여 만든 로그인 상태 관리 (기록용)

  • navigation.js (Store.js)
import { Provider, useSelector } from "react-redux"
import { createStore } from "redux"

  function reducer(state = IsLogin, action) {
    // state 상태 변경
    if (action.type === "로그인") {
      state = true
      console.log(state)
      // MainPageTrue()
      return state
    } else if (action.type === "로그아웃") {
      state = false
      console.log(state)
      LoginTrue()
      return state
    } else return state
  }

  let store = createStore(reducer)

return (
<>
 <Provider store={store}>
        <Container>
          <LoginModal isModal={LoginModalIsOpen} setModal={setLoginModalOpen} />

          <MainPageModal
            isModal={MainPageModalIsOpen}
            setModal={setMainPageModalOpen}
          />

          <NoticeModal
            isModal={NoticeModalIsOpen}
            setModal={setNoticeModalOpen}
          />

          <MyInformationModal
            isModal={MyInformationModalIsOpen}
            setModal={setMyInformationModalOpen}
          />

          <ChallengeModal
            isModal={ChallengeModalIsOpen}
            setModal={setChallengeModalOpen}
          />

          <BoardModal isModal={BoardModalIsOpen} setModal={setBoardModalOpen} />

          <BoardList
            isModal={BoardListModalIsOpen}
            setModal={setBoardListModalOpen}
          />

          <PushUpModal
            isModal={PushUpModalIsOpen}
            setModal={setPushUpModalOpen}
          />

          <SitupModal isModal={SitUpModalIsOpen} setModal={setSitUpModalOpen} />

          <SquatModal isModal={SquatModalIsOpen} setModal={setSquatModalOpen} />

          <SignupModal
            isModal={SignupModalIsOpen}
            setModal={setSignupModalOpen}
          />
        </Container>
      </Provider>
<>
)              
  • Login.js (Login Component)
import { useDispatch } from "react-redux"

  // 로그인 상태 변화 (dispatch)
  const dispatch = useDispatch()

  // 일반 이메일 로그인
  const onSubmit = async (event) => {
    try {
      let data
      // login => 로그인 화면
      data = await authService.signInWithEmailAndPassword(ID, PW)
      window.alert("로그인 성공")
      dispatch({ type: "로그인" })
      console.log(data)
    } catch (error) {
      console.log(error)
      window.alert("이메일과 비밀번호를 다시 확인해주세요")
    }
  }

  // 소셜 로그인 Google & Facebook
  const auth = getAuth()
  const user = auth.currentUser

  const onSocialClick = async (event) => {
    const {
      target: { name },
    } = event
    let provider
    if (name === "google") {
      provider = new firebaseInstance.auth.GoogleAuthProvider()
      await authService.signInWithPopup(provider)
      // MainPageTrue()
      dispatch({ type: "로그인" })
    } else if (name === "facebook") {
      provider = new firebaseInstance.auth.FacebookAuthProvider()
      await authService.signInWithPopup(provider)
      dispatch({ type: "로그인" })
    }
    window.alert("로그인 성공")

    UserImage = user.photoURL // 프로필 사진 URL
    UserName = user.displayName // 표시 이름
    UserEmail = user.email // 이메일
  }

Menubar.js

import { useSelector } from "react-redux"

function Menubar() {
  console.log("Menubar")
  const selectorData = useSelector((state) => state)
  const [data, setData] = useState(selectorData)

  useEffect(() => {
    setData(selectorData)
  }, [selectorData])

  return (
    <>
      <MenuBar>
        <Symbol src={Logo} />
        <MenuBtn1
          onClick={() => {
            data === true ? MainPageTrue() : LoginTrue()
          }}

          로그인
        </MenuBtn1>
        <MenuBtn2
          onClick={() => {
            NoticeTrue()
          }}

          공지사항
        </MenuBtn2>
        <MenuBtn3
          onClick={() => {
            data === true
              ? InformationTrue()
              : window.alert("로그인이 필요한 페이지 입니다.")
          }}

          내정보
        </MenuBtn3>
        <MenuBtn4
          onClick={() => {
            data === true
              ? ChallengeTrue()
              : window.alert("로그인이 필요한 페이지 입니다.")
          }}

          챌린지
        </MenuBtn4>
        <MenuBtn5
          onClick={() => {
            data === true
              ? BoardTrue()
              : window.alert("로그인이 필요한 페이지 입니다.")
          }}

          소통 게시판
        </MenuBtn5>
      </MenuBar>
    </>
  )
}

export default Menubar

05.겪었던 에러

  • useEffect 내부에서는 useSelector를 사용할려고 하니 이러한 에러 메시지가 출력 됐다.

Error
React Hook "useSelector" cannot be called inside a callback. React Hooks must be called in a React function component or a custom React Hook function
응답 후크 "선택기 사용"은 콜백 내에서 호출할 수 없습니다. 반응 후크는 반응 기능 구성 요소 또는 사용자 지정 반응 후크 기능에서 호출되어야 합니다.

해결 방안

  const selectorData = useSelector((state) => state)
  const [data, setData] = useState(selectorData)

  useEffect(() => {
    setData(selectorData)
  }, [selectorData])
profile
일취월장(日就月將) - 「날마다 달마다 성장하고 발전한다.」

0개의 댓글