Project : helprogrammers - 상세 페이지
· 약 3분
❤️🔥TIL : Today I Learned
🤢 문제 내용
문제 참 많았다... 정리해 보자면
나는 게시글을 클릭 했을 때, router 가 변하며 해당 라우터에서 상세 내용(제목,내용,시간 등..) 을 보여주는 페이지의 crud 기능 구현을 맡게 되었다.
문제는 이렇게 흘러갔다
- 해당 컴포넌트 렌더링 될 때 useLocation 사용하여
axios.get요청 문제점 - 다른 액션 발생할 때(delete, update) 추후 데이터 수정의 어려움을 깨닫게 됨 - thunk를 사용하여
detailSlice.js생성하여 부모컴포넌트에서 onClick이 이루어 질 때dispatch(__getDetail)문제점 - 상세페이지에서 새로고침 하면 state 값이 리셋되어 결국 새로고침을 하면 상세페이지 내용 없어짐 - 1번에서 가져온 방식보다 더 깔끔하게
useParams사용하여 쉽게 id 가져와dispatch(__getDetail(id))해결
🔨 시도한 방법 (코드 변천사)
- 해당 컴포넌트 렌더링 될 때
useLocation사용하여axios.get요청
Question.jsx
const location = useLocation();
const dispatch = useDispatch();
// state 값
const [questionState, setQuestionState] = useState('');
// useEfect로 컴포넌트 렌더링 시 axios 데이터 받아오기
useEffect(() => {
const getData = async () => {
const { data } = await axios.get(
`http://localhost:3001/questions${location.pathname}`,
);
// 받은데이터 state로 업로드
setQuestionState(data);
};
getData();
}, []);
- thunk를 사용하여
detailSlice.js생성
ListCard.jsx
import { useDispatch } from 'react-redux';
import { Link } from 'react-router-dom';
import { useSelector } from 'react-redux';
import { __getDetail } from '../redux/module/DetailSlice';
const ListCard = ({ question }) => {
const dispatch = useDispatch();
const onClickEvent = (id) => {
dispatch(__getDetail(id));
};
return (
<QuestionLink to={`/${question.id}`}> // Detail.jsx 컴포넌트 이동
<Thread onClick={() => onClickEvent(question.id)}>
);
}
🎈 문제 해결 방법
useParams사용하여 쉽게 id 가져온 후,dispatch(__getDetail(id))
Detail.jsx
import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { __deleteDetail, __getDetail } from '../redux/module/DetailSlice';
import { useParams } from 'react-router-dom';
const Detail = () => {
const dispatch = useDispatch();
// 구조분해 할당
const { isLoading, error, question } = useSelector((state) => state.detail);
const { id } = useParams();
// component mount 즉시 코드 실행
useEffect(() => {
dispatch(__getDetail(id));
}, []);
if (isLoading) {
return <div>로딩 중..</div>;
}
if (error) {
return <div>존재하지 않는 페이지 입니다..</div>;
}
return <div>이하 생략..</div>;
};
detailSlice.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import axios from 'axios';
const serverUrl = 'http://localhost:3001/questions';
// question 이라는 state 생성
const initialState = {
question: [],
isLoading: false,
error: null,
};
export const __getDetail = createAsyncThunk(
'GET_DETAIL',
async (payload, thunkAPI) => {
try {
const data = await axios.get(
`${serverUrl}/${payload}`, // payload로 전달 받은 id 값 가져오기
);
return thunkAPI.fulfillWithValue(data.data);
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
},
);
export const detailSlice = createSlice({
name: 'detail',
initialState,
reducers: {},
extraReducers: {
// read
[__getDetail.pending]: (state) => {
state.isLoading = true; // 네트워크 요청이 시작되면 로딩상태를 true로 변경합니다.
},
[__getDetail.fulfilled]: (state, action) => {
state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다.
state.question = action.payload; // question state에 payload로 받은 id값 저장
},
[__getDetail.rejected]: (state, action) => {
state.isLoading = false; // 에러가 발생했지만, 네트워크 요청이 끝났으니, false로 변경합니다.
state.error = action.payload; // catch 된 error 객체를 state.error에 넣습니다.
},
},
});
export const detail = detailSlice.actions;
export default detailSlice.reducer;
✨ 알게된 것
여기서 보면 question 이라는 state에 업데이트를 하는 것을 알 수 있다. state는 임시 저장과 같은 원리라서 새로고침이 된다면 state에 있는 데이터는 다 날아간다..
그래서 상세페이지(Detail.jsx) 컴포넌트가 mount 될 때 useParams() 함수로 가져온 아이디를 useEffect를 활용해 바로 __getDetail( id )을 실행해서 해당 state를 업데이트 할 수 있도록 업데이트 해줬다
그래서 새로고침이 되더라도 useEffect 는 실행이 되므로 state는 업데이트가 되어있는 상태로 표시되어
해결
새로고침시 아무것도 안남게 되는 문제를 해결했다!
