티스토리 뷰

TIL/React

[리액트 React] 엑시오스 (Axios)

개춘기뽀삐 2024. 2. 19. 21:30
설치 명령어
npm install json-server

포트 변경
npx json-server db.json --port 4000

서버 접속
http://localhost:4000/

 

axios와 json-server로 CRUD 만들기


.env

  • 외부로 알려지면 안 되는 API_KEY나 db관련 정보 등등 보안이 필요한 값들을 보안이나 유지 보수를 용이하게 하기 위해 환경변수로 만들어 변수를 꺼내와 사용하는 것
  • 서버 주소 값을 REACT_APP_SERVER_URL 변수에 담아 프로젝트 전반에서 변수명으로 주소에 모두 접근이 가능하다
.env 파일
REACT_APP_SERVER_URL=http://localhost:4000

 

Get

  1. useEffect으로 컴포넌트가 마운트 될 때 비동기 통신 함수실행시켜 서버에 데이터를 요청함
  2. 요청한 데이터를 콘솔로 확인해 원하는 데이터의 키를 찾음(data)
  3. 데이터를 컴포넌트에서 사용하기 위해 state를 만들어줌
  4. 서버에서 받아온 데이터를 state에 담아서 컴포넌트에 데이터를 뿌려준다
  5. useEffect은 return을 먼저 읽고 실행되기 때문에 서버에서 받아온 데이터가 없는 상태로 map을 돌려서 콘솔에 오류가 찍힘 옵셔널 함수를 통해 해결 (todos?.map : todos가 있으면 맵을 돌려라)
import axios from "axios";
import React, { useEffect, useState } from "react";
// Get - 데이터 가져오기

function App() {
  // 받아온 데이터를 컴포넌트 안에서 state로 사용하기 위해 state에 담아줌
  const [todos, setTodos] = useState(null);

  // 비동기 통신 함수
  const fetchTodos = async () => {
    // 서버에 요청한 값이 담긴 data를 구조분해 할당으로 변수에 담음
    const { data } = await axios.get("http://localhost:4000/todos");

    // 서버에서 받아온 데이터를 state에 담음
    setTodos(data);

    console.log("data", data);
    // const response = await axios.get("http://localhost:4000/todos");
    // 콘솔로 response를 확인해보면 객체 형태로 되어있는 값에 원하는 데이터는 data:{}으로 들어가있음, 그러니 data 값만 빼오기 위해 구조분해 할당을 한 것
  };

  useEffect(() => {
    // 최초 마운트 될 때(렌더링) 비동기 통신 함수를 작동시켜 db값을 가져온다
    fetchTodos();
  }, []);

  return (
    <div>
      {todos?.map((item) => {
        return (
          <div key={item.id}>
            {item.id} : {item.title}
          </div>
        );
      })}
    </div>
  );
}

export default App;

 

Post

  1. db에 넣을 데이터를 만들기 위해 state생성
  2. state에 들어갈 값은 json 형식을 맞추기 위해 객체형태로 key를 넣어주고 value에 state 값이 들어간다
  3. 위와 마찬가지로 input에 입력될 값도 onChange 함수에 setState를 json 형식에 맞춰 값을 넣어준다 {title:e.target.value}
  4. * state 변경으로는 데이터를 추가하면 db에 입력된 id를 state가 바로 가져오지 못하기 때문에 state 변경 대신 데이터 조회 함수를 다시 실행시킨다 
import axios from "axios";
import React, { useEffect, useState } from "react";
// POST - 데이터 등록

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

  // 데이터 가져오기
  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:4000/todos");
    setTodos(data);
    console.log("data", data);
  };

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

  // Json 서버에 데이터 등록하기

  const [inputValue, setInputValue] = useState({
    // noSQL의 경우 id값은 자동으로 넣어주기때문에 따로 넣어줄 필요가 없다(Ex. firebase)

    // 이미 등록된 json 방식으로 값을 넣어주기 위해 객체로 만들고 title키에 inputValue 값을 넣어줄것
    title: "",
  });

  // 추가함수

  // 추가 버튼 클릭시 input에 입력된 (state에 저장된) 값을 db에 저장 (post 요청)
  const onSubmitHandler = async () => {
    // newTodo를 만들지 않은 이유는 inputValue 자체가 새 객체이기때문에 새 객체를 생성할 필요가 없음 title(key)에 value로 input값을 넣어주기때문

    await axios.post("http://localhost:4000/todos", inputValue);
    // 데이터 추가 후 새로고침해야 추가된 데이터가 나오는 이유는 state의 상태 변화가 없기때문에 리렌더링이 일어나지 않기 때문. 그래서 데이터 추가 후 state의 상태도 변경해주면 리렌더링돼서 새로고침을 하지 않아도 된다.
    // setTodos([...todos, inputValue]);

    // *** state 변경으로는 데이터를 추가하면 db에 입력된 id를 state가 바로 가져오지 못하기때문에 state 변경 대신 데이터 조회 함수를 다시 실행 시킨다
    fetchTodos();
  };

  return (
    <>
      <div>
        {/* 데이터 등록 부분(INPUT) */}
        <form
          onSubmit={(e) => {
            e.preventDefault();

            // 추가 버튼 클릭 시 submit 이벤트 실행
            onSubmitHandler();
          }}
        >
          <input
            type="text"
            value={inputValue.title}
            onChange={(e) => {
              setInputValue({ title: e.target.value });
            }}
          />
          <button type="submit">추가</button>
        </form>
      </div>

      {/* 데이터 출력 부분(OUTPUT) */}
      {todos?.map((item) => {
        return (
          <div key={item.id}>
            {item.id} : {item.title}
          </div>
        );
      })}
    </>
  );
}

export default App;

 

Delete

  1. form 안에 버튼은 submit으로만 작동하기 때문에 주의해야 한다
  2. 삭제 버튼 클릭 시 삭제 기준을 함수에 매개변수로 보내주고(id) filter를 통해 state의 상태를 변경시킨다
import axios from "axios";
import React, { useEffect, useState } from "react";
//  delete - 데이터 삭제

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

  // 데이터 가져오기
  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:4000/todos");
    setTodos(data);
    console.log("data", data);
  };

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

  // 데이터 추가하기
  const [inputValue, setInputValue] = useState({
    title: "",
  });

  // 추가 함수
  const onSubmitHandler = async () => {
    await axios.post("http://localhost:4000/todos", inputValue);
    fetchTodos();
  };

  // 데이터 삭제하기
  const onDeleteHandler = async (id) => {
    axios.delete(`http://localhost:4000/todos/${id}`);
    setTodos(
      todos.filter((item) => {
        return item.id !== id;
      })
    );
  };

  return (
    <>
      <div>
        {/* 데이터 등록 부분(INPUT) */}
        <form
          onSubmit={(e) => {
            e.preventDefault();
            onSubmitHandler();
          }}
        >
          <input
            type="text"
            value={inputValue.title}
            onChange={(e) => {
              setInputValue({ title: e.target.value });
            }}
          />
          <button type="submit">추가</button>
        </form>
      </div>

      {/* 데이터 출력 부분(OUTPUT) */}
      {todos?.map((item) => {
        return (
          <div key={item.id}>
            {item.id} : {item.title}
            {/* 삭제 버튼 */}
            &nbsp;&nbsp;&nbsp;
            <button
              onClick={() => {
                onDeleteHandler(item.id);
              }}
            >
              삭제
            </button>
            {/* <button onClick={onDeleteHandler(item.id)}>삭제</button> */}
            {/* 함수에 인자를 보낼때 위와 같이 작성할 경우 렌더링 시 함수를 먼저 실행시켜버리기떄문에 한번 더 함수로 감싸줘야한다 */}
          </div>
        );
      })}
    </>
  );
}

export default App;

 

Patch

  1. 수정할 데이터의 id와 내용을 state를 생성하여 담는다
  2. 버튼 클릭 시 state에 담은 값으로 id를 가져오고 수정된 내용은 객체형태로 담아주면 된다 {title(키) : 바꿀내용}
  3. state 상태 변경을 위해 map을 이용하여 수정된 데이터는 전개구문으로 수정된 title을 새로운 객체에 담아주고 수정되지 않은 값은 map함수의 인자 그대로 반환하면 된다
import axios from "axios";
import React, { useEffect, useState } from "react";
//  patch - 데이터 수정

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

  // 데이터 가져오기
  const fetchTodos = async () => {
    const { data } = await axios.get("http://localhost:4000/todos");
    setTodos(data);
    console.log("data", data);
  };

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

  // 데이터 추가하기
  const [inputValue, setInputValue] = useState({
    title: "",
  });

  // 추가 함수
  const onSubmitHandler = async () => {
    await axios.post("http://localhost:4000/todos", inputValue);
    fetchTodos();
  };

  // 데이터 삭제하기
  const onDeleteHandler = async (id) => {
    axios.delete(`http://localhost:4000/todos/${id}`);
    setTodos(
      todos.filter((item) => {
        return item.id !== id;
      })
    );
  };

  // 데이터 수정하기

  // 수정할 데이터의 id값을 담을 state
  const [targetId, setTargetId] = useState("");

  // 수정할 데이터의 내용을 담을 state
  const [content, setContent] = useState("");

  // 수정 함수
  const onUpdateHandler = async () => {
    // 수정할 id와 content는 state에 저장되어있기 때문에 todos에서 인자로 받을 필요가 없다

    await axios.patch(`http://localhost:4000/todos/${targetId}`, {
      title: content,
    });

    setTodos(
      todos.map((item) => {
        if (item.id === targetId) {
          return { ...item, title: content };
        } else {
          return item;
        }
      })
    );
  };

  return (
    <>
      <div>
        {/* 데이터 수정 */}
        <input
          type="text"
          value={targetId}
          onChange={(e) => {
            setTargetId(e.target.value);
          }}
          placeholder="수정할 id"
        />

        <input
          type="text"
          value={content}
          onChange={(e) => {
            setContent(e.target.value);
          }}
          placeholder="수정할 내용"
        />
        <button onClick={onUpdateHandler}>수정</button>
      </div>
      <br />

      <div>
        {/* 데이터 등록 부분(INPUT) */}
        <form
          onSubmit={(e) => {
            e.preventDefault();
            onSubmitHandler();
          }}
        >
          <input
            type="text"
            value={inputValue.title}
            onChange={(e) => {
              setInputValue({ title: e.target.value });
            }}
          />
          <button type="submit">추가</button>
        </form>
      </div>

      {/* 데이터 출력 부분(OUTPUT) */}
      {todos?.map((item) => {
        return (
          <div key={item.id}>
            {item.id} : {item.title}
            {/* 삭제 버튼 */}
            &nbsp;&nbsp;&nbsp;
            <button
              onClick={() => {
                onDeleteHandler(item.id);
              }}
            >
              삭제
            </button>
          </div>
        );
      })}
    </>
  );
}

export default App;

 

 

Interceptor

요청-응답 사이에 값을 넣는 등의 기능을 추가하는 것

  • 위 코드에 axios가 있던 자리에 가공된 axios(api)를 넣어준다  Ex. axios.get() = > api.get()
  • api에 baseURL로 서버 주소를 넣어줬기 때문에 서버 주소 입력 부분도 생략이 가능하다
  • Ex. api.get(`${process.env.REACT_APP_SERVER_URL}/todos`); => api.get("/todos")
import axios from "axios";

// baseURL에 담긴 값을 사용하기 위해 axios를 인스턴스로(객체) 가공하여 만든다
//baseURL에 담긴 값은 .env 환경 설정 파일에 담긴 서버 주소임
const instance = axios.create({
  baseURL: process.env.REACT_APP_SERVER_URL,

  // 요청 시 응답이 오기까지 기다리는 시간, 입력된 시간을 초과할 경우 오류 메세지가 출력됨
  timeout: 1,
});

// interceptors를 이용해 요청-응답 사이에 값을 넣는 등. 관여해보기

// 요청(request)
instance.interceptors.request.use(
  // 요청을 보내기 전 수행되는 함수
  function (config) {
    console.log("인터셉터 요청 성공!");
    return config;
  },

  // 오류 요청을 보내기 전 수행되는 함수
  function (error) {
    console.log("인터셉터 요청 오류!");
    return Promise.reject(error);
    // 오류는 꼭 return Promise.reject 처리를 해줘야 한다
  }
);

// 응답(response)
instance.interceptors.response.use(
  // 응답을 내보내기 전 수행되는 함수
  function (response) {
    console.log("인터셉터 응답 성공!");
    return response;
  },

  // 오류 응답을 내보내기 전 수행되는 함수
  function (error) {
    console.log("인터셉터 응답 오류!");
    return Promise.reject(error);
  }
);

export default instance;
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
글 보관함