[TIL 2022. 12. 14] Axios와 React, Redux-Toolkit 사용 (CRD 구현)

김헤일리·2022년 12월 14일
1

TIL

목록 보기
12/46

드디어 주특기 심화 과정을 시작하면서 팀 과제를 하게 되었다.
지금까지의 프로젝트 중 정말 역대급으로 어렵고... 3주만에 리액트 과정을 끝낸다는 항해가 정말 믿기지 않을 정도로 CRUD를 내 스스로가 구현한다는 것은 어려운 일이었다.

  • 프로젝트는 나만의 일기장 컨셉인데, 게시글 CRUD와 댓글 CRUD가 메인 기능이었다.
  • 그 중 내가 맡은 부분은 게시글 CRUD고, 그 중 Update가 가장 어렵기 때문이 이 포스팅엔 일단 CRD만 작성하려고 한다.

1. 게시글 보여주기 (Axios GET, Read 구현 부분)

❗️ READ의 화면 부분

  • 사용자가 게시글을 작성하면 작성된 게시글이 게시판 형태로 화면에 뿌려지는 코드다.
function CardList() {
  // 1. 게시글을 하나의 card로 보고, CardList라는 함수명을 사용했다.
  
  const dispatch = useDispatch();
  // 2. useDispatch는 생성한 action을 호출하는 용도로 사용하기 때문에, dispatch라는 변수에 선언해서 담아둔다.
  
  const { isLoading, error, diary } = useSelector((state) => state.diary);
  // 3. slice 파일에서 만든 initialState를 전역 상태로 만들어서 Store에 올려둔 상황.
  // 3-1. useSelector를 이용해서 Store에 있는 상태의 값을 조회할 수 있다.
  // 3-2. initialState 중 diary에 해당하는 값을 조회

  useEffect(() => {
    dispatch(getDiary());
  }, [dispatch]);
  // 4. useEffect를 이용하면 의존성 배열에 있는 값이 실행될 때 함수 내부에 있는 로직이 실행된다.
  // 4-1. dispatch가 일어날때마다 getDiary함수를 실행하기 위한 dispatch가 실행된다는 뜻!
  

  if (isLoading) {
    return <div>로딩 중....</div>;
  }
  // 5. 만약 initialState에 지정되었던 isLoading이 false일 경우, 화면에 "로딩 중..."이 표시된다.

  if (error) {
    return <div>{error.message}</div>;
  }
  // 6. 만약 initialState에 있던 error가 생길 경우, 해당 에러에 해당하는 메세지를 화면에 출력한다.
  // 6-1. ex. 404 not found

  return (
    <DiaryBox>
      <h3>일기리스트</h3>
      <LinkDiv>
        <Link to="/write/:id" className="datail">
   		// 7. [일기 쓰기]라는 글을 <Link> 태그로 감싸서 버튼의 역할을 할 수 있도록 만든다.
    	// 7-1. [일기 쓰기] 클릭 시 이동하는 페이지는 새로운 일기를 작성할 수 있는 페이지
          <span>일기쓰기</span>
        </Link>
      </LinkDiv>
      <LinkDiv>
        <StListContainer>
          {diary.map((item) => (
    	// 8. store에 저장된 diary는 배열이기 때문에 map을 돌려서 배열 안에 있는 정보를 나열한다.
    	// 8-1. 이때 diary라는 배열안에 있는 하나의 요소는 item이라는 변수로 지정한다. 
    	// (일기 전체 = diary), (일기 1개 = item) 
            <Link key={item.id} to={`/details/${item.id}`}>
			// 8-2. map을 통해 나열된 요소를 <Link> 태그로 감싸서 div 자체를 클릭할 경우 상세 페이지로 이동할 수 있게 한다.
              <StList>
                <div>
                  <div style={{ marginBottom: '10px' }}>{item.id}번째 일기</div>
				  // 8-3. map을 돌릴 경우, 나열되는 item 하나하나에 고유 아이디 값을 부여한다. 
				  // 8-4. 이때 부여되는 아이디값은 일기가 생성될 때 저절로 생성되는 id 번호
                  <div style={{ fontSize: '1.2rem', marginBottom: '10px' }}>
                    일기 제목: {item.title}
				 // 8-5. 일기의 제목을 표시하기 위해 item의 속성값 중 title을 가져온다.
				 // 8-6. 객체의 속성을 빼올 땐 item.title과 같은 형식을 사용한다.
                  </div>
                  <div style={{ width: '1000px' }}>{item.content}</div>
				// 8-7. 일기 내용을 가져오기 위해 item의 속성 중 content를 가져온다.
                </div>
                <Button
                  color="rgb(255, 128, 129)"
                  onClick={() => {
                    onDelete(item.id);
                  }}
                >
                  삭제
                </Button>
              </StList>
            </Link>
          ))}
        </StListContainer>
      </LinkDiv>
    </DiaryBox>
  );
}

❗️READ의 slice 파일 부분

const initialState = {
  diary: [ // 1. slice 파일에 있는 diary의 initialState 중 diary다.
    {
      id: 1, // 1-1. 다이어리의 고유값
      title: 'diary', // 1-2. 다이어리의 제목
      content: 'write diary', // 1-3. 다이어리의 내용
    },
  ], // 1-4. diary는 객체를 품고있는 배열이다.
  
  detail: {
    id: 1,
    title: 'title',
    content: 'content',
  },
  isLoading: false,
  error: null,
};

export const getDiary = createAsyncThunk(
// 2. getDiary라는 변수에 비동기처리를 할 수 있는 함수인 createAsyncThunk()를 할당한다.
// 2-1. createAsyncThunk는 리덕스 툴킷에 내장되어있는 미들웨어이다. 
  'diary/getDiary', 
  // 2-2. createAsyncThunk()를 활용하게되면 첫번째 매개변수로 액션의 이름 (액션밸류)를 정의한다.
  // 2-3. createAsyncThunk()를 활용할 경우, 선언한 액션 이름에 pending, fulfilled, rejected에 대한 action을 자동으로 부여한다. 
  // 2-4. 리덕스에서 액션은 상태에 어떤 변화가 필요할 때 발생되어야 하는 객체이다. 액션 객체엔 해당 객체의 type이 필수적으로 지정되어야하고, 객체에 들어갈 다른 값은 개발자의 필요에 따라서 지정된다.
  async (payload, thunkAPI) => {
  // 3. createAsyncThunk의 두번째 매개변수는 미들웨어가 처리할 비동기 함수이고, 실행 결과를 promise 형식으로 반환한다.
  // 3-1. 처리할 비동기 함수에 넣는 매개변수는 해당 함수가 리턴할 값 (통칭 payload)과 promise 형태로 반환할 thunkAPI이다.
    try {
      // 4. try/catch/finally문을 사용해서 에러 핸들링을 할 수 있다. (필수 요소는 아니다.)
      const response = await axios.get('http://localhost:3001/diary'); 
      // 5. aync 함수 내부에는 axios를 이용해서 특정 api와 연결할때 어떤 method를 요청할 지 설정하는 변수를 선언한다.
      // 5-1. 여기서 response라는 상수는 get 요청을 하겠다! 라는 뜻 자체를 담고있다.
      console.log(response);
      // 5-2. data를 콘솔에 찍어보면 axios가 가져오는 요청값 (config) 정보를 갖고있다.
      return thunkAPI.fulfillWithValue(response.data); 
      // 6. promise에서 네트워크 요청이 성공한 경우 dispatch하고, 인자로는 payload가 들어간다.
      // 6-1. 디스패치는 액션과 페이로드를 리듀서에게 전달하는 과정이다.
      // 6-2. axios의 요청 config중 data는 요청 바디로 전달할 데이터를 담고 있다.
      // 6-3. extraReducer로 response라는 변수에 담긴 값에서 data로 정의된 부분을 보낸다.
    } catch (error) {
      console.log(error);
      return thunkAPI.rejectWithValue(error); 
      // 7. promise에서 네트워크 요청이 실패한 경우, 원하는 값을 리턴해주고, 여기서는 리턴하는 인자로 catch에서 주는 error를 리턴하게 만들었다.
    }
  },
);


export const diarySlice = createSlice({
  // 8. createSlice 메서드는 initialState, reducer 함수들의 객체, slice 이름을 받아서 이에 상응하는 action creator와 action type을 자동으로 생성한다.
  name: 'diary',
  // 9. 
  initialState,
  reducers: {},
  extraReducers: {
    // 10. thunk 함수를 사용하는 경우엔 일반 리듀서가 아니라 extraReducers가 필요하다. 
    // 10-1. promise가 반환하는 진행중, 성공, 실패 케이스에 대해서 리듀서를 만든다.
    [getDiary.pending]: (state) => {
      state.isLoading = true; 
      // 11. 네트워크 요청이 시작되면 로딩상태를 true로 변경한다. (initialState, 즉 state의 상태값이기 때문에 state.isLoading)
    },
    [getDiary.fulfilled]: (state, action) => {
      state.isLoading = false; 
      // 12. 네트워크 요청이 끝났으니 false로 변경한다.
      state.diary = action.payload;
      // 12-1. Store에 있는 diary에 서버에서 가져온 새로운 diary를 넣는다.
      // 12-2. action의 payload를 initalState에 있는 diary에 넣는다. 
      // 12-3. action.payload는 변경된 행동(action)의 값(payload = 변경된값)을 의미한다.
    },
    [getDiary.rejected]: (state, action) => {
      state.isLoading = false; 
      // 13. 에러가 발생했지만, 네트워크 요청이 끝났으니, false로 변경한다.
      state.error = action.payload; 
      // 13-1. catch 된 error 객체를 state.error에 넣어서 error 값을 출력한다.
    },


2. 게시글 상세 페이지 보여주기 (Axios GET, READ 구현 부분)

❗️ READ - Detail 화면 부분

function CommentList() {
  const params = useParams();
  // 1. 특정 일기를 선택했을 때 해당 일기에 대한 상세 페이지로 이동하기 위해서 url의 parameter를 가져올 수 있는 useParams를 선언한다.
  const detailId = useSelector((state) => state.diary.detail);
  // 2. store에 게시글 1개에 대한 diary라는 initialState에 배열이 아닌 하나의 객체를 담는detail을 만든다.
  // 2-1. detailId에 useSelector를 이용해서 store에서 조회하는 detail의 값을 할당한다.

  const dispatch = useDispatch();
  // 3. 액션 함수를 실행해서 store에 변경된 값을 지정하려면 dispatch를 사용해야 한다.
  // 3-1. useDispatch 훅을 dispatch라는 변수에 담아서 사용한다.
  
  useEffect(() => {
  // 4. useEffect 사용 시, 컴포넌트가 나타나거나, 사라지거나, 업데이트 됐을 때 특정 작업을 실행할 수 있다.
    dispatch(getDiaryId(params.id));
    // 4-1. 컴포넌트에 변경이 있을 경우, getDiaryId 함수를 실행한다. 
    // 4-2. 해당 함수 실행 시 params로 가져온 url의 id 값 (파라미터)를 매개변수로 보낸다.
  }, [dispatch, params.id]);
  // 4-3. 의존성 배열에 넣어둔 값이 변경될 때 useEffect 내부에 있는 함수가 실행된다.
  // 4-4. 처음 mount 될 때와 getDiaryId() dispatch가 실행될 때 컴포넌트가 다시 렌더링된다.

  return (
    <DiaryDetail>
      <LinkDiv>
        <Link to="/">
          <Button color="#ff8b8b">돌아가기</Button>
        </Link>
        <Link to={`/details/${detailId.id}/update/`}>
          <Button color="#61bfad" onClick={onEditHandler}>
            다시 쓰기
          </Button>
        </Link>
      </LinkDiv>
      <DetailDiv>
        <Diary>
          <div style={{ marginBottom: '15x' }}>{detailId.id}번째 일기</div>
		  // 5. 일기 1개의 값을 가져오기 때문에 detailId에서 id값 추출
          <div className="title" style={{ fontSize: '2rem', marginBottom: '20px' }}>
            {detailId.title}
			// 5-1. 일기 1개의 값을 가져오기 때문에 detailId에서 title값 추출
          </div>
          <div className="content" style={{ fontSize: '1rem', marginBottom: '15px' }}>
            {detailId.content}
			// 5-2. 일기 1개의 값을 가져오기 때문에 detailId에서 content값 추출
          </div>
        </Diary>

❗️ READ - Detail slice 부분

const initialState = {
  diary: [
    {
      id: 1,
      title: 'diary',
      content: 'write diary',
    },
  ],
  detail: { // 1. slice 파일에 있는 diary의 initialState 중 일기 1개만을 가져오기 위한 detail이다.
    id: 1, // 1-1. 해당 일기의 아이디값
    title: 'title', // 1-2. 해당 일기의 제목
    content: 'content', // 1-3. 해당 일기의 내용
  }, // 1-4. detail은 일기 1개를 의미하기 때문에 배열이 아닌 객체이다.
  isLoading: false, 
  error: null,
};

export const getDiaryId = createAsyncThunk(
// 2. getDiaryId라는 변수에 비동기 함수 createAsyncThunk 함수 할당
  'diary/getDiaryId', 
  // 2-1. 비동기 함수의 첫번째 매개변수로 액션 밸류 정의
  async (detailId, thunkAPI) => {
  // 3. 비동기 함수의 두번째 매개변수로 미들웨어가 처리할 또 다른 비동기 함수 할당.
  // 3-1. aync 함수의 매개변수는 컴포넌트 파일에서 dispatch로 실행할 때 넘겨준 매개변수(detailId)와 결과물을 promise로 반환할 thunkAPI를 준다.
  const response = await axios.get(`http://localhost:3001/diary/${detailId}`, detailId);
  // 4. 미들웨어가 처리하는 비동기 함수 내부 로직에 response라는 상수를 선언하고, 해당 상수에 axios를 통해 연결할 api 주소와 method를 정의.
  // 4-1. axios와 연결되는 함수의 첫번째 매개변수로 api 주소 할당.
  // 4-2. api 주소 할당 시, 특정 일기의 페이지임을 명시하기 위해 url의 parameter로 detailId를 할당한다.
  // 4-3. detailId는 특정 일기의 아이디값이기 때문에, 서버에 전달할 값이기 때문에 두번째 매개변수에 할당해서 서버로 필요한 정보를 보낸다.
  return thunkAPI.fulfillWithValue(response.data);
  // 5. 요청이 성공할 경우, 받아온 response의 요청 config 중 data를 뽑아서 엑스트라 리듀서로 보낸다.
});

export const diarySlice = createSlice({
  name: 'diary',
  initialState,
  reducers: {},
  extraReducers: {
    [getDiaryId.fulfilled]: (state, action) => {
    // 6. getDiaryId가 성공할 경우, state와 action을 매개변수로 둔다.
      state.detail = action.payload;
      // 6-1. store에 등록된 state에서 detail값을 가져온다.
      // 6-2. 기존의 상태값에 action(diary/getDiaryId)을 통해 받아온 payload (함수를 통해 리턴된 값)을 대입한다.
      // 6-3. 기존 상태값에 새로운 값이 대입됐기 때문에 store에 등록된 state를 변경시키는 것.
    },


3. 게시글 작성하기 (Axios POST, Create 구현 부분)

❗️ CREATE의 화면 부분

function WriteCard() {
  const [title, setTitle] = useState('');
  // 1. 일기를 새로 생성하기 때문에 일기의 제목을 state로 관리하도록 한다.
  // 1-1. state는 컴포넌트의 현재 상황에 대한 정보를 나타내기 위해 리액트에서 쓰는 일반 자바스크립트 객체다. 
  const [content, setContent] = useState('');
  // 2. 일기의 내용도 state로 관리한다.
  // 2-1. 관리되는 값은 content, content가 변경되는 경우 setContent에 담아서 후자가 전자를 변경할 수 있도록 한다.

  const dispatch = useDispatch();

  const onSubmitHandler = (event) => {
  // 6. 저장 버튼을 클릭할 경우 실행되는 함수다.
  // 6-1. 버튼에서 일어난 이벤트 (click)을 매개변수로 받아서 클릭이 일어날 경우 함수 내부 로직이 실행된다.
    const newDiary = { title, content };
    // 6-2. 새로운 일기를 저장하기 위해 생성한 함수이기 때문에 일단 새로운 일기의 값이 저장될 수 있는 상수를 선언한다.
    // 6-3. 해당 상수는 객체의 형태로 각각 title과 content라는 키에 title과 content라는 값을 담는다.
    // 6-4. 인풋필드와 textarea의 입력되는 value가 title과 content가 되도록 지정했기 때문에 newDiary에 동일하게 담긴다.
    if (title === '' || content === '') {
    // 6-5. 만약 title과 content에 담긴 내역이 공백일 경우:
      alert('제목과 타이틀을 모두 작성해주세요.');
      // 6-6. 알림창이 생성된다.
    } else {
      // 6-6. 만약 담긴 내역이 공백이 아닐 경우:
      dispatch(postDiary(newDiary));
      // 6-7. dispatch를 통해 slice 파일에 있는 postDiary 함수를 호출한다.
      // 6-8. postDiary 함수 호출 시 newDiary를 매개변수로 보낸다.
      window.location.replace('/');
      // 6-9. dispatch가 완료되면 새로고침을 활용해서 메인 페이지로 보내버린다.
    }
  };

  return (
    <DiaryWrite>
      <h2
        style={{
          display: 'flex',
          flexDirection: 'column',
          justifyContent: 'center',
          alignItems: 'center',
        }}
      >
        일기 작성
      </h2>
      <LinkDiv>
        <Link to="/" className="datail">
          <span>그만쓰기</span>
        </Link>
        <Button type="submit" color="rgb(78, 183, 164)" onClick={onSubmitHandler}>
        // 5. 저장 버튼을 클릭하면 onSubmitHandler가 실행된다.
          저장
        </Button>
      </LinkDiv>
      <StInputContainer>
        <Input
		// 3. 일기의 제목을 작성할 수 있는 인풋필드를 만든다
          id="title"
          name="DiaryTitle"
          label="제목"
          value={title}
		  // 3-1. 해당 인풋에 기입되는 값을 useState로 관리하고 있는 값 중 title로 지정한다.
          onChange={(event) => {
          // 3-2. 해당 인풋에서 변화되는 값을 detect하기 위해 onChange 이벤트 핸들러를 사용한다. 
            setTitle(event.target.value);
            // 3-3. 해당 target에서 일어나는 event중 value가 변경되는 것을 감지하고 변경된 값을 setTitle에 담는다.
            // 3-4. setTitle에 담기기 때문에 인풋필드에 기입한 내용이 title의 값으로 지정된다.
          }}
        />
        <textarea
		// 4. 일기의 내용을 작성할 수 있는 textarea를 만든다.
          value={content}
		  // 4-1. 해당 textarea에 기입되는 값을 useState로 관리하고 있는 값 중 content로 지정한다.
          onChange={(event) => {
            setContent(event.target.value);
            // 4-2. target에서 일어나는 event 중 value가 변경되는 것을 감지해서 변경된 값을 setContent에 담는다.
           // 4-3. setContent에 담았기 때문에 textarea에 작성한 내용이 content의 값으로 지정된다.
          }}
        />
      </StInputContainer>
    </DiaryWrite>
  );
}

❗️ CREATE의 slice 부분

const initialState = {
  diary: [
    {
      id: 1,
      title: 'diary',
      content: 'write diary',
    },
  ],
  detail: {
    id: 1,
    title: 'title',
    content: 'content',
  },
  isLoading: false,
  error: null,
};


export const postDiary = createAsyncThunk(
// 1. postDiary라는 상수에 비동기 함수 createAsyncThunk 함수 할당
  'diary/postDiary', 
  // 2. 비동기 함수의 첫번째 매개변수로 액션 밸류 정의
  async (newDiary, thunkAPI) => {
  // 3. 두번째 매개변수로 미들웨어가 처리할 또 다른 비동기 함수 할당
  // 3-1. aync 함수의 매개변수는 컴포넌트 파일에서 dispatch로 실행할 때 넘겨준 매개변수 newDiary.
  // 3-2. 두번째 매개변수를 결과물을 promise로 반환하는 thunkAPI. 
    try {
    // 4. 만약 실행이 잘 될 경우:
      const response = await axios.post('http://localhost:3001/diary', newDiary);
      // 4-1. reponse라는 상수에 axios를 통해 연결할 api 주소와 method를 함수의 첫번째 매개변수로 정의한다.
      // 4-2. axios와 연결되는 함수의 두번째 매개변수로 서버에 전달할 값 (newDiary)를 보낸다.
      return thunkAPI.fulfillWithValue(response.data);
      // 4-3. 서버와 연결이 잘된 경우, response에 담긴 config 중 data를 뽑아서 리듀서로 보낸다.
    } catch (error) {
      // 5. 비동기 함수가 처리될 때 에러가 생길 경우:
      return thunkAPI.rejectWithValue(error);
      // 5-1. 연결 실패 케이스로 에러를 담아서 리듀서에 보낸다.
    }
});

export const diarySlice = createSlice({
  name: 'diary',
  initialState,
  reducers: {},
  extraReducers: {
	[postDiary.fulfilled]: (state, action) => {
    // 6. postDiary가 성공할 경우 실행되는 리듀서로, 매개변수에 state와 action을 둔다.
      state.diary = { diary: [...state.diary, action.payload] };
      // 6-1. 그리고 받아온 값을 이용해서 기존 diary state에 새로운 값을 담는다.
      // 6-2. diary는 객체 (일기 1개)를 여러개 갖고 있는 배열이기 때문에 diary를 먼저 둔다.
      // 6-3. 그 다음 배열 안에 있던 기존 객체를 보존하기 위해 전개 연산자로 기존 state를 펼친다.
      // 6-4. 그리고 배열에 새로운 값 (newDiary)을 payload에 담아서 배열에 추가한다.
    },
    [postDiary.rejected]: (state, action) => {
    // 7. postDiary가 실패할 경우 실행되는 리듀서로, 매개변수에 동일하게 state와 action을 둔다.
      state.error = action.payload;
      // 7-1. 기존 state에 있는 error (null로 설정되어있음)에 실패시 받아오는 payload를 대입한다.
    },


4. 게시글 삭제하기 (Axios DELETE, DELETE 구현 부분)

❗️ DELETE의 화면 부분

function CardList() {
  const dispatch = useDispatch();
  // 1. useDispatch는 생성한 action을 호출하는 용도로 사용하기 때문에, dispatch라는 변수에 선언해서 담아둔다.
  const { isLoading, error, diary } = useSelector((state) => state.diary);
  // 2. slice 파일에서 만든 initialState를 전역 상태로 만들어서 Store에 올려둔 상황.
  // 2-1. useSelector를 이용해서 Store에 있는 상태의 값을 조회할 수 있다.
  // 2-2. initialState 중 diary에 해당하는 값을 조회

  const onDelete = (itemId) => {
  // 4return문 내부에 있는 삭제버튼을 클릭할 경우 실행되는 함수.
  // 4-1. 함수 실행 시 받아오는 매개변수를 itemId라는 변수에 담는다.
    console.log(itemId);
    // 4-3. 이때 콘솔에 변수를 출력하면 return문에서 받아온 item(일기 1개)의 id값이 출력된다.
    dispatch(deleteDiary(itemId)).then(() => {
    // 4-4. onDelete 함수 안에 있는 내용은 slice 파일에 있는 deleteDiary를 호출하는 내용이다.
    // 4-5. 이때 deleteDiary() 함수에 itemId를 매개변수로 보낸다.
    // 4-6. .then()은 . 이전에 표시된 함수의 실행이 완료된 후 then() 내부에 있는 함수를 실행시킨다는 뜻.
      window.location.replace('/');
      // 4-7. 여기서 then() 내부에 있는 함수는 페이지 새로고침 함수이다.
    });
  };

  return (
    <StListContainer>
          {diary.map((item) => (
            <Link key={item.id} to={`/details/${item.id}`}>
              <StList>
                <div>
                  <div style={{ marginBottom: '10px' }}>{item.id}번째 일기</div>
                  <div style={{ fontSize: '1.2rem', marginBottom: '10px' }}>
                    일기 제목: {item.title}
                  </div>
                  <div style={{ width: '1000px' }}>{item.content}</div>
                </div>
                <DiaryBox>
                    <Button
                     color="rgb(255, 128, 129)"
                     onClick={() => {
                       onDelete(item.id);
                     }}
                    >
                       삭제
                    // 3. [삭제] 버튼을 클릭 하면 onDelete 함수가 실행된다. 
					// 3-1. 해당 함수에 map을 돌렸던 diary에서 하나의 요소인 item의 id를 매개변수로 보낸다.
                    </Button>
		       </StList>
            </Link>
          ))}
    </StListContainer>
  );
}

❗️ DELETE의 slice 부분

const initialState = {
  diary: [
    {
      id: 1,
      title: 'diary',
      content: 'write diary',
    },
  ],
  detail: {
    id: 1,
    title: 'title',
    content: 'content',
  },
  isLoading: false,
  error: null,
};

export const deleteDiary = createAsyncThunk(
// 1. deleteDiary라는 상수에 비동기 함수 createAsyncThunk 함수 할당
  'diary/deleteDiary', 
  // 2. 비동기 함수의 첫번째 매개변수로 액션 밸류 정의
  async (itemId, { dispatch }) => {
  // 3. 두번째 매개변수로 미들웨어가 처리할 또 다들 비동기 함수 할당
  // 3-1. async 함수의 매개변수는 컴포넌트 파일에서 dispatch로 실행할 때 넘겨준 매개변수 itemId
  // 3-1. 두번째 매개변수로는 dispatch를 객체에 담아서 전달한다.
  try {
    const response = await axios.delete(`http://localhost:3001/diary/${itemId}`);
    // 4. response라는 상수에 axios를 통해 연결할 메소드 타입과 api주소를 주고, 해당 주소의 parameter로 itemId를 할당한다.
    dispatch(getDiary());
    // 4-1.  axios delete 요청을 보낸 후 다시 한번 일기 전체리스트를 조회하게 만들어서 아무런 값을 넘기지 않은 상태로 diary 배열을 호출한다.
    // 4-2. payload로 아무런 값을 전달하지 않았기 때문에 store에 있는 diary에 새로운 값이 추가되지 않아서 작성된 일기가 사라진것처럼 만든다.
  } catch (error) {
    console.log(error);
  }
});


첫 팀과제라 매우 비효율적인 코드이고, 정말 구동만..될 수 있는 코드를 먼저 짜보았다.
결과물은 매우 미흡하지만, 적어도 axios를 사용하는 방법은 조금 더 배울 수 있는 그런 시간이었다.

profile
공부하느라 녹는 중... 밖에 안 나가서 버섯 피는 중... 🍄

0개의 댓글