TIL-React(4)

January·2022년 8월 13일
0

Frontend

목록 보기
17/31
post-custom-banner

Reducer와 context

Reducer 상태관리

하나의 데이터가 어떤 작업을 하는지는 코드를 살펴봐야지만 알 수 있다. (데이터 추가, 제거, 수정..등) 그래서 하나로 모아서 관리가 되도록 useReducer를 쓴다. useReducer는 상태관리 및 데이터 추가,제거,수정 등의 각종 Handler를 하나의 함수로 사용할 수 있다. 미리 어떤 동작을 하나의 데이터를 통해서 가능하게 할 건지 정해놓을 수 있다.

상태관리 라이브러리에도 동일하게 적용되는 원리이다.

const [state, dispatch] = useReducer(리듀서 이름, 초기 데이터)

dispatch는 데이터 추가,제거,수정 등을 위한 함수이다. 데이터 제거 사용법은 dispatch({type:’REMOVE’}) 이렇게 하고 추가는 dispatch({type:’ADD’}) 이렇게 한다.

데이터와 관련한 작업을 명시해 놓는 곳이 Reducer인거다. 그래서 dispatch에 동작을 명시하면 함수안에 명시한 return값을 수행한다.

// Reducer 파일
// dispatch({ type: 'ADD, data: 새로운 데이터 }) -> action = 1
export function userReducer(state, action) {
  switch (action.type) {
    case 'ADD':
      return [...state, action.data]
	case 'REMOVE':
	  return ~~~
    default:
      throw new Error(`Unhandled action type: ${action.type}`)
  }
}
// Reducer 활용 예시
import React, { useReducer, useState } from 'react'
import { userData } from '../constants/userData'
import { userReducer } from '../reducers/userReducer'

function UserList() {
  const [userInput, setUserInput] = useState({id: '', name: '', email: ''})
  const userInputHandler = (e) => {
    const {name, value} = e.target
    setUserInput({...userInput, [name]: value})
  }
  const [state, dispatch] = useReducer(userReducer, userData)

  return (
    <div>
      {state.map((user) => {
        return <p key={user.id}>{user.name}</p>
      })}
      <input name="name" onChange={userInputHandler} />
      <input name="emali" onChange={userInputHandler} />
      <button onClick={() => dispatch({type:'ADD', data: userInput})}>추가하기</button>
    </div>
  )
}

export default UserList

useContext

특정한 값을 모든 컴포넌트에서 사용할 수 있도록 만들어놓고, 어떤 컴포넌트에서든 값을 건내주는 Hook이다. props drilling을 방지할 수 있다. props drilling

// 상위 컴포넌트
import { useReducer, createContext } from 'react';
import UserList from './components/UserList';
import { userData } from './constants/userData';
import { userReducer } from './reducers/userReducer';

// 다양한 컴포넌트에서 사용해야해서 밖에다 만든다.
export const UserContext = createContext()

function App() {

  const [state, dispatch] = useReducer(userReducer, userData)

  return (
    <UserContext.Provider value={{ state, dispatch }}>
      <UserList />
    </UserContext.Provider>
  );
}

// 하위 컴포넌트
import { UserContext } from '../App'

function UserInfo() {
  const { count } = useContext(UserContext)
  return (
    <p>{count}</p>
  )
}

export default UserInfo

그렇다고 해서 항상 useContext 를 써야하는건 아니다.

정말로 전 컴포넌트에서 공유되어야 하는 값이 있을 때만 사용하는 것이고, 각 컴포넌트로 별로만 관리하는 값이라면 그냥 useState 를 쓰는 것이 더 적절하다

// useContext 단순화
// app.js
import UserList from './components/UserList';
import { UserProvider } from './contexts/UserContext';

function App() {
  return (
    <UserProvider>
      <UserList />
    </UserProvider>
  );
}

export default App;

// UserContext.jsx
import { useReducer, createContext } from 'react';
import { userData } from '../constants/userData';
import { userReducer } from '../reducers/userReducer';

// 다양한 컴포넌트에서 사용해야해서 밖에다 만든다.
export const UserContext = createContext()

export function UserProvider({ children }) {
  const [state, dispatch] = useReducer(userReducer, userData)

  return (
    <UserContext.Provider value={{ state, dispatch }}>
      { children }
    </UserContext.Provider>
  );
}

useState는 상태가 변화면 다시 렌더링을 한다. 그래서 컴포넌트를 분리하면 분리할 수록 좋은 점은 해당 컴포넌트만 렌더링 되기 때문에 훨씬 더 효율적이다. 현재 컴포넌트 구조는 UserList만 하위컴포넌트로 있는데 제공된 값이 변하면 하위구조의 컴포넌트가 전부다 렌더링이 새로 되기 때문에 useContext를 남발하면 안되는 이유이다.

이런 문제들을 해결하기 위해 다양한 상태관리 라이브러리들이 등장했다.

Axios 요청

useEffect로 axios 요청을 하면 index.jsStrictMode가 useEffect가 잘 작동하는지 확인하기 위해 두번 실행을 시킨다. 디버깅 과정을 위해 있는 건데 프로덕션 빌드에서는 필요하지 않아서 지워도 괜찮다. 그럼 요청이 한번만 간다.

네트워크 에러

CORS Error는 동일한 오리진에서 보낸 요청이 아니면 거부를 한다. 카카오 서비스를 만들었을때 카카오채팅 기록은 카카오톡에서만 가져올 수 있다. localhost, dev 서버에서 api요청하는거랑 실제 주소로 요청하는 서로의 주소값이 다르다는 에러이다.

package.json에 "proxy": "https://apis.data.go.kr/"를 추가해주면 이주소를 거쳐서 요청을 보내게 된다. 그러면 axios를 쓸때 요청 주소에 중복되는 주소를 지워도 된다. 내가 있는곳이 proxy 주소라는 의미. 그럼 CORS 에러는 해결했다.

CORS는 왜 이렇게 우리를 힘들게 하는걸까?

react query

로딩, 데이터, 에러 관리하는 라이브러리

post-custom-banner

0개의 댓글