즐코

React-router / redux 상태관리 라이브러리 맛보기 본문

React

React-router / redux 상태관리 라이브러리 맛보기

YJLEE_KR 2022. 5. 3. 14:12

1. react router 만들기

2. redux 맛보기

 

1. react router 만들기

 

1. react-router-dom

: 클라이언트의 URL 요청에 따라 페이지를 렌더해주기 위한 모듈

(SPA를 위한 react 이므로 새로운 페이지를 렌더할 때 새로고침이 아닌 한 화면에서 데이터만 바꿔주는 형태이다)

npm install react-router-dom 로 설치

 

2. BrowserRouter / Link / Routes / Route 라우터를 react-router-dom에서 가져온다.

 

- BrowserRouter : 최상위 컴포넌트로서 history API를 사용하여 url 과 ui를 동기화하는 라우터

- Link : A 태그 대신 써야하는 컴포넌트 (to 속성에 설정된 링크로 이동 / history스택에 저장된다고함)

- Routes : 자식 컴포넌트 Route와 매치되는 첫번째 요소를 렌더링해줌

- Route : 컴포넌트의 path 속성으로 들어간 url에 맞는 컴포넌트/함수를 찾아서 렌더링해줌

  <Route path='경로url' element={해당 path에 맞춰서 렌더할 컴포넌트} />

   => 이건 라우터 역할만 해주기 때문에 화면에 렌더해주진 않는다. 따라서 화면에 렌더할 컴포넌트를 당연히 따로 만들어줘야함

 

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Index from './pages/index';
import Counter from './pages/counter';
import Comment from './pages/comment';
import Login from './pages/login';
import Header from './components/common/header';

function App() {
  return (
    <>
      <Router>
        <Header /> {/* 렌더할 컴포넌트가 Routes위에 오게끔 */}
        <Routes>
          <Route path='/' element={<Index />} />
          <Route path='/counter' element={<Counter />} />
          <Route path='/comment' element={<Comment />} />
          <Route path='/login' element={<Login />} />
        </Routes>
      </Router>
    </>
  );
}

export default App;

 

 

2. redux 맛보기 

 

redux : 상태 관리를 도와주는 라이브러리 

 

redux가 없다면 각 컴포넌트에서 개별적으로 상태 관리를 해주어야하는데,

redux로 상태 관리 전용 디렉토리/파일 (store)에 전역 상태를 관리하고, 각 컴포넌트에선 이걸 보여주기만 하면 된다!

 

npm install redux react-redux 두 개의 라이브러리를 깔아주자 

 

 

1. 데이터가 저장되는 공간 만들어주기 (보통은 store라는 디렉토리/파일로 만든다고함)

 

createStore(reducer,옵션들) : 모든 상태를 담고 있는 리덕스가 제공하는 저장공간을 만들어주는 메소드 (한 앱에서 하나밖에 못쓴다)

 

인자1. rootReducer

: combineReducers() 로 합친 reducer (인자로 초기값도 가져옴 state=initialState / reducer 코드 참고)

 

인자2. 옵션 composeWithDevTools

: 이건 없어도 그만 있어도 그만, 하지만 개발자관리도구에서 redux를 좀 더 다양하게 활용하고 싶다면 넣는 옵션

- npm install redux-devtools-extension 으로 설치 : redux store를 직접 관리할 수 있게 도와주는 개발자관리도구

- action 다시 실행, state 상태 비교 등등

 

- 전역 상태인 store를 적용하려면 <Provider 태그 + store 옵션 설정>으로 App 컴포넌트를 감싸줘야함 (이거때문에 에러남)

- 여기선 Provider 안에 여러 컴포넌트가 들어갈 예정이라 children을 활용함

- Provider 는 react-redux 라이브러리에서 끌고 온다

 

import { createStore } from 'redux'
import rootReducer from '../reducers/rootReducer'
import { composeWithDevTools } from 'redux-devtools-extension'
import { Provider } from 'react-redux'

const store = createStore(rootReducer, composeWithDevTools())

const Store = ({ children }) => {
 return (
   <Provider store={store}>
     {children}
   </Provider>
  )
}

export default Store

 

 

2. 전역 상태 변경 함수 reducer 만들어주기 

 

1- reducer 도 전역 상태 변경을 해주는 함수이므로 Store처럼 따로 빼준다.

   보통 각 컴포넌트별로 reducer를 작성해서 이걸 합쳐준다고 한다. 합쳐주는 메소드는 redux 라이브러리에서 제공해줌

   combineReducers({ reducer1, reducer2 ... })

 

2- 각각의 개별 reducer

  - state, action을 인자로 받아서 state를 변경한다.

  - state : 한마디로 상태를 보여준다. 초기값 (initialState)도 보통 이 reducer에서 선언한다.

  - action : 무슨 기능/동작이 요청되었는지 알려주는 객체이다. action의 type 속성은 무슨 동작을 할지 알려주는 역할이다.

  

* 아래 rootReducer는 리얼 rootReducer는 아니고, 우선 counter 컴포넌트만을 위한 reducer만 넣어둠

 

const initialState = {
  number: 0
}

const UP = 'COUNTER/UP'
const DOWN = 'COUNTER/DOWN'

// 액션 생성함수
export const up = () => ({ type: 'COUNTER/UP' })
export const down = () => ({ type: 'COUNTER/DOWN' })

const rootReducer = (state = initialState, action) => {
  switch (action.type) {
    case UP:
      return {
        ...state,
        number: state.number + 1
      }
    case DOWN:
      return {
        ...state,
        number: state.number - 1
      }
    default:
      return state
  }
}

export default rootReducer

  

 

3. reducer 쓰기 (각 컴포넌트에서 전역 상태 활용 및 변경하기)

  

react-redux에서 제공하는 함수 활용한다 - useSelector & useDispatch

 

useSelector(콜백함수) : state를 조회해준다.

useDispatch() : dispatch객체를 만들어준다. 이걸로 전역 상태 변경을 하면 된다. (reducer에게 action.type 전달)

 

import { useSelector, useDispatch } from "react-redux"
import { up, down } from "../../reducers/rootReducer"
import Responsive from "../../components/common/Responsive"

const Counter = () => {
  const counter = useSelector((state) => state)
  const dispatch = useDispatch()

  const increase = () => {
    dispatch(up())
  }

  const decrease = () => {
    dispatch(down())
  }

  return (
    <>
      <Responsive>
        <h3> Counter : {counter.number}</h3>
        <button onClick={increase}>+1</button>
        <button onClick={decrease}>-1</button>
      </Responsive>
    </>
  )
}

export default Counter

 

여기서 끝난줄 알았는데,, 오류 발생..

Uncaught Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>

 

각 컴포넌트가 전역상태를 확인하고 변경하려면 전역객체 Provider로 감싸져야한다..그걸 간과해서 에러가 난 건데 찾는데 꽤 오래 걸렸다.

App 컴포넌트를 전역 객체 Store (Provider) 로 감싸주면 해결됨

 

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import Store from './store/useStore';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Store> 
      <App />
    </Store>
  </React.StrictMode>
);

 

'React' 카테고리의 다른 글

useRef 복습 - 변수관리 (state와는 다르다!)  (0) 2022.05.11
useEffect 복습  (0) 2022.05.10
redux-middleware (redux-thunk)  (0) 2022.05.04
props와 state  (0) 2022.04.13
리액트 기초오브기초  (0) 2022.04.13
Comments