[TIL] 내일배움캠프 React 과정 2022.12.18_Axios

Today I Learned

  • React 심화 강의 수강

 


Axios 이해하기

Axios란?

공식문서에서는 axios를 node.js와 브라우저를 위한 Promise 기반 http 클라이언트라고 소개하고 있다. 다시 말해 http를 이용해서 서버와 통신하기 위해 사용하는 패키지라고 생각하시면 된다.

 

 

 Axios GET 

// url에는 서버의 url이 들어가고, config에는 기타 여러가지 설정을 추가할 수 있다.
// config는 axios 공식문서에서 확인한다.
axios.get(url[, config]) // GET

 

get서버의 데이터를 조회할 때 사용한다.

Axios config 공식문서 소개 링크

 

// src/App.js
import React, { useEffect, useState } from "react";
import axios from "axios"; // axios를 import 한다.

const App = () => {
  const [todos, setTodos] = useState(null);

  // axios를 통해서 get 요청을 하는 함수를 생성한다.
  // 비동기처리를 해야하므로 async/await 구문을 통해서 처리한다.
  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:3001/todos");
    setTodos(data); // 서버로부터 fetching한 데이터를 useState의 state로 set 합니다.
  };
	
  // 생성한 함수를 컴포넌트가 mount 됐을 떄 실행하기 위해 useEffect를 사용한다.
  useEffect(() => {
    fetchTodos(); // effect 구문에 생성한 함수를 넣어 실행합니다.
  }, []);

  // data fetching이 정상적으로 되었는지 콘솔을 통해 확인합니다.
  console.log(todos); 
  
  return <div>App</div>;
};

export default App;

json-server에 있는 todos를 axios를 이용해서 fetching하고 useState를 통해서 setState하는 로직이다.

 

콘솔에 다음과 같이 데이터가 찍히는 것을 볼 수 있다.

 

 

 Axios POST 

axios.post(url[, data[, config]])   // POST

axios.post

post는 서버에 데이터를 추가할 때 사용한다. 보통은 클라이언트의 데이터를 body 형태로 서버에 보내고자 할 때 사용하는 것이다.

json-server의 POST 요청 방식

 

const App = () => {

  // 새롭게 생성하는 todo를 관리하는 state
  const [todo, setTodo] = useState({title: "",});

  const [todos, setTodos] = useState(null);

  const onSubmitHandler = async(todo) => {
    // 이때 todos 안에 todo는 1개다.
    await axios.post("http://localhost:3001/todos", todo); 
		
    // 여기서 서버 요청이 끝나면 서버의 todos 안에 todo는 2개가 된다.
    
    //새로고침해서 진짜 현재 서버 데이터를 받아오기 전에 상태를 똑같이 동기시켜 준다
	setTodos([...todos, todo]) 2. <-- 만약 이게 없다면, go to useEffect
  };

  useEffect(() => {
    // 새로고침해서 여기를 다시 실행해줘야 서버값이 새로 들어온다.
    fetchTodos(); 
  }, []);

  return (
    <>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          onSubmitHandler(todo);
        }}
      >
        <input
          type="text"
          onChange={(ev) => {
            const { value } = ev.target;
            setTodo({
              ...todo,
              title: value,
            });
          }}
        />
        <button>추가하기</button>
      </form>
      
      <div>
        {todos?.map((todo) => (
          <div key={todo.id}>{todo.title}</div>
        ))}
      </div>
    </>
  );
};

화면에 input과 버튼이 있고, input에 어떤 값을 넣고 버튼을 클릭했을 때 onSubmitHandler 이 실행된다. onSubmitHandler 함수의 목적은 todo를 body에 담아 서버로 POST 요청을 보내는 것이다.

 

 

post 요청 보냈을 때 네트워크 탭의 로그 확인하기

네트워크 쪽 개발을 할 때는 항상 브라우저에 있는 네트워크 탭을 확인하면서 개발을 진행하는 것이 좋다. 어떤 문제가 생겼을 때 이정보를 통해 디버깅을 할 수 있기 때문이다.

 

Header

  • Request URL을 통해서 의도한 URL로 post 요청을 보냈음을 알 수 있다.
  • Request Method를 통해서 POST 메서드를 사용했음을 알 수 있다.
  • Status Code를 통해서 201 코드를 받았고, 정상적으로 네트워크가 이루어졌음을 알 수 있다. status code는 자동으로 생성되는 것이 아니라 BE개발자가 직접 개발을 하고 설정한 code가 브라우저에게 보이게 된다. 그래서 만약 BE개발자가 구현을 해놓지 않았다면 문맥과 다른 status code가 브라우저에 보일 수 있다.

 

Payload

payload에서는 보낸 body를 확인 할 수 있다.

 

Response

response에서는 보낸 post에 요청에 대한 서버의 응답 값을 확인할 수 있다. 이 Response 값은 자동으로 생성되는 것이 아니라, FE 개발자가 BE 개발자에게 요청한 것을 직접 개발을 해야 생기는 값이다. 현재 사용한 json-server의 경우 POST 요청을 했을 때 클라이언트가 보낸 body를 그대로 응답해 주도록 만들어진 패키지이기 때문에 위와 같이 표시된다.

 

 

 Axios DELETE 

axios.delete(url[, config])  // DELETE

DELETE저장되어 있는 데이터를 삭제하고자 요청을 보낼 때 사용한다.

 

const App = () => {
  const [todo, setTodo] = useState({
    title: "",
  });

  const [todos, setTodos] = useState(null);

  // 삭제 버튼 이벤트 핸들러 
  const onClickDeleteButtonHandler = (todoId) => {
    axios.delete(`http://localhost:3001/todos/${todoId}`);
    setTodos(todos.filter((todo) => todo.id !== id))
  };

  useEffect(() => {
    fetchTodos();
  }, []);

  return (
    <>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          onSubmitHandler(todo);
        }}
      >
        <input
          type="text"
          onChange={(ev) => {
            const { value } = ev.target;
            setTodo({
              ...todo,
              title: value,
            });
          }}
        />
        <button>추가하기</button>
      </form>
      <div>
        {todos?.map((todo) => (
          <div key={todo.id}>
            {todo.title}
            {/* 삭제 버튼 추가 */}
            <button
              onClick={() => onClickDeleteButtonHandler(todo.id)}
            >
              삭제하기
            </button>
          </div>
        ))}
      </div>
    </>
  );
};

 

 

 Axios PATCH 

axios.patch(url[, data[, config]])  // PATCH

patch는 어떤 데이터를 수정하고자 서버에 요청을 보낼 때 사용하는 메서드이다.

 

patch와 동일한 원리로 작동하는 put 메서드가 있는데

PATCH는 기존 데이터를 유지하면서 요청하는 부분만 업데이트하고,

PUT은 리소스의 모든 것을 업데이트한다.

 

{
  "title": "타코야끼",
  "id": "mmEWX6Y"
},

만약에 다음과 같은 구조의 데이터에서 PUT 메서드를 이용해서 title의 값만 변경한다면 id는 기존 값이 유지되지 않고 null이 된다.

 

const App = () => {
  const [todo, setTodo] = useState({
    title: "",
  });
  const [todos, setTodos] = useState(null);

  // patch에서 사용할 id, 수정값의 state를 추가
  const [targetId, setTargetId] = useState(null);
  const [editTodo, setEditTodo] = useState({
    title: "",
  });

  // 수정버튼 이벤트 핸들러 추가 👇
  const onClickEditButtonHandler = (todoId, edit) => {
    axios.patch(`http://localhost:3001/todos/${todoId}`, edit);
    
    let copy = [...todos]
    const editTodo = copy.map((list) => 
      list.id === todoId ? edit : list
    );
    setTodos(editTodo);
  };

  useEffect(() => {
    fetchTodos();
  }, []);

  return (
    <>
      <form
        onSubmit={(e) => {
          e.preventDefault();
          onSubmitHandler(todo);
        }}
      >
        {/* 👇 수정기능에 필요한 id, 수정값 input2개와 수정하기 버튼을 추가 */}
        <div>
          <input
            type="text"
            placeholder="수정하고싶은 Todo ID"
            onChange={(ev) => {
              setTargetId(ev.target.value);
            }}
          />
          <input
            type="text"
            placeholder="수정값 입력"
            onChange={(ev) => {
              setEditTodo({
                ...editTodo,
                title: ev.target.value,
              });
            }}
          />
          <button
            // type='button' 을 추가해야 form의 영향에서 벗어남
            type="button"
            onClick={() => onClickEditButtonHandler(targetId, editTodo)}
          >
            수정하기
          </button>
        </div>
        <input
          type="text"
          onChange={(ev) => {
            const { value } = ev.target;
            setTodo({
              ...todo,
              title: value,
            });
          }}
        />
        <button>추가하기</button>
      </form>
      <div>
        {todos?.map((todo) => (
          <div key={todo.id}>
            {/* todo의 아이디를 화면에 표시 */}
            {todo.id} :{todo.title}
            <button
              type="button"
              onClick={() => onClickDeleteButtonHandler(todo.id)}
            >
              삭제하기
            </button>
          </div>
        ))}
      </div>
    </>
  );
};

export default App;

Todo를 수정하기 위해 필요한 데이터는 2개가 있다. 수정하고자 하는 Todo의 id, 그리고 수정하고자 하는 값이다. 수정하고자 하는 값은 기존에 있던 todo라는 state를 사용하고, id는 직접 입력을 해서 url로 넘겨주는 방식으로 구현할 것이다. 보통은 수정 기능을 구현할 때 직접 id를 입력받아 처리는 방식은 거의 없지만 이번 예시에서는 아주 간단한 코드로 기능을 구현하는 것이기 때문에 위와 같이 처리하는 것이다.

 

 

.env (환경변수 관리)란?

env는 API key, port, DB 등 민감한 정보를 환경변수에 담아 관리하는 방법이다. env를 이용해서 API 서버의 IP 또는 URL을 숨겨서 처리할 수 있다.

출처 https://tooo1.tistory.com/582

 

 

Axios 정리하기

  • Axios를 이용해서 API 서버와 통신할 수 있다.
  • Axios는 http 통신을 도와주는 패키지이며, 구체적인 명세는 API 명세서를 확인해야 한다.
  • 브라우저 네트워크 탭을 잘 봐야 한다.
  • http method, staus code와 같은 정보들은 BE개발자가 구현해주는 부분이며, 약속이자 문맥이므로 BE와 FE 간의 커뮤니케이션이 잘 되어야 한다.
  • 네트워크 통신 이후, 화면을 업데이트 하고자 한다면 별도로 FE에서 추가로 구현해야 한다.

네트워크 통신 이후 새로고침 없이 화면을 업데이트하기 위해 각 함수마다 setState를 사용했다.

 


Programmers 문제 풀기

짝수의 합

 
function solution(n) {
    let answer = 0;
    for ( i = 2; i <= n; i += 2 ) {
        answer += i
    }
    return answer
}

for문을 짝수만 돌리고 싶다면 final-expression을  i += 2;로 설정하면 된다.

 

 

중복된 숫자 개수

나의 풀이

function solution(array, n) {
    let answer = 0;
    for ( const num of array) {
        if ( num === n ) {
            answer += 1;
        }
    }
    return answer
}

 

다른 사람의 풀이

function solution(array, n) {
    var answer = 0;
    let Array = array.filter((item) => item === n)
    answer = Array.length
    return answer;
}

filter() 메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.

나는 filter는 익숙해지지 않아서 잘 사용안하는 거 같다. 앞으로는 filtet 이용해서 문제 풀어보는 연습도 해야겠다.

 

function solution(array, n) {
    return array.filter(v=>v===n).length;
}

위의 filter를 이용한 풀이 방법을 더 간략하게 작성하면 이렇게 된다.

 


회고

Programmers 스파르타에서 매일 지정해주는 문제 푸는 것을 포기하고 그냥 정답률 높은 순으로 차근차근 풀기로 했다. 스파르타에서 지정해주는 문제 풀면 팀원들이랑 상의하며 풀 수 있어서 좋긴 한데 너무 어려운 문제를 올려주니까 자꾸 알고리즘이 싫어지려고 해서ㅎㅎ 그냥 쉬운 문제부터 풀려고 한다.

 

얏호

오늘은 어제 너무 놀았던 거 같아서 오전부터 나와서 공부했다. 제일 큰 산인 aixos와 thunk를 공부했기 때문에 만족스러운 하루였다. 지금 리액트 심화 강의를 5강까지 들었는데 수강 랭킹 1위도 해봤다! ㅎㅎ 일단 강의를 다 듣고 TIL에 내용을 정리하며 공부하긴 했지만 지금 머릿속에서 aixos와 json-server, thunk가 뒤죽박죽 섞인 상태다. 아직 전체적인 흐름도 이해되지 않고 세부적으로 의문인 부분도 많다. 월요일에 튜터님들께 질문할 사항을 잔뜩 준비해뒀다. 🙊 프로젝트 시작 전에 심화 과정을 이해하려면 정말 열심히 해야 할 거 같다!