todosSlice와 commentsStlice와 유사하여 commentsSlice 위주로 작성(comments가 조금 더 복잡했음.)
export const __addComments = createAsyncThunk(
"comments/addComments",
async (payload, thunkAPI) => {
try {
const data = await axios.post(params.key, payload);
// payload를 comments.jsx에서 obj로 받아 바로 더하기
// 공통 : params.key는 .env에 숨겨놓은 local url(배포때는 바꿈)
return thunkAPI.fulfillWithValue(data.data);
// 객체로 변환해서 return 해 줌
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
...
...
(extraReducer pt)
[__addComments.fulfilled]: (state, action) => {
state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다.
state.commentList.push(action.payload); // 교체가 아니라 추가하는거다.
export const __getComments = createAsyncThunk(
"comments/getComments",
async (payload, thunkAPI) => {
try {
const data = await axios.get(params.key);
const selCommentList = data.data.filter((val) => {
return Number(payload) === Number(val.commentId);
});
return thunkAPI.fulfillWithValue(selCommentList);
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
export const __editComments = createAsyncThunk(
"comments/editComments",
async (payload, thunkAPI) => {
// id와 수정값 payload로 받아 옴
try {
const params = {
key: process.env.REACT_APP_COMMENT,
};
await axios.patch(`${params.key}/${payload.id}`, payload.editComment);
const data = await axios.get(params.key);
// 수정한 이후 갑을 한 번 더 받아옴
const filterData = data.data.filter((val) => {
return val.id === payload;
});
// filter로 id 값이 같은 것만 수정할 수 있게 함
return thunkAPI.fulfillWithValue(filterData.body);
// data의 body 값을 return
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
export const __deleteComments = createAsyncThunk(
"comments/deleteComments",
async (payload, thunkAPI) => {
// payload로 id 받아온다.
try {
const params = {
key: process.env.REACT_APP_COMMENT,
};
const data = await axios.delete(`${params.key}/${payload}`);
// delete 이용해서 id 값 지워준다.
return thunkAPI.fulfillWithValue(payload);
// data.data를 넘겨주는게 아니라 아래서 쓸 id, 즉 payload를 넘겨준다.
} catch (error) {
return thunkAPI.rejectWithValue(error);
}
}
);
...
...
[__deleteComments.fulfilled]: (state, action) => {
state.isLoading = false; // 네트워크 요청이 끝났으니, false로 변경합니다.
state.commentList = state.commentList.filter(
(item) => item.id !== action.payload
);
// 바로 지워지려면 state.commentList를 설정...
// 서버 단에서 지우는게 있고 리덕스에서 지우는게 따로 있다.
const { isLoading, error, todos } = useSelector((state) => state.todos);
//id최대값
const getMaxId = () => {
let stateIdArr = todos.map((element) => {
// useSelect 한 todos map 돌린 후 거기서 나온 id를 리턴해서 전개연산함
return Number(element.id);
});
return Math.max(...stateIdArr);
};
....
....
const obj = {
id: getMaxId() + 1,
title: title.title,
body: body.body,
writer: writer.writer,
};
// 오련 식
const params = {
key: process.env.REACT_APP_COMMENT,
};
.env를 루트 디렉토리에 만든 뒤
REACTAPP변수명= "url"
로 설정해준다.
아쉬운 점 : .gitIgnore에 숨겨야 하는데 숨기면 창이 안 떠서 못 숨겼다... 어떻게 방법이 없었을까...
comment delete 예시
const onClickDelButtonHandler = (id) => {
dispatch(__deleteComments(id))
};
그 외에도 다양한 방식으로 dispatch를 다른 훅과 매개변수와 조합해서 씀.(useEffect 등)
onClick={() => {
const result = window.confirm("이 댓글을 지울까요?");
if (result) {
return onClickDelButtonHandler(item.id);
} else {
return;
}
}}
취소 / 확인 alert를 만들어주는 메서드인듯. 유용하게 썼다. 쓰는 법 잘 익혀놓으면 좋을 것 같다. 꼭 window를 먼저 써주길.
(TodoDetail.jsx)
// ⭐️prev는 setDetail의 이전 값을 가져오는 것
// 업데이트 시키기 전에 처음에 있던 state 값을 prev로 가져올 수 있음.
// prev의 무슨 값을 넣든 이전 값을 가져옴
setDetail((prev) => ({
...prev,
body: editTodo.body,
}));
(TodoList.jsx)
onClick={(event) => {
event.stopPropagation();
// 이벤트 버블링을 막는 법. 삭제, 여백 등 같이 있을 때 이벤트가 퍼질 때 막는 것
(useInput.js)
import React, { useState } from "react";
const useInput = () => {
// 2. value는 useState로 관리,
const [tempName, setName] = useState({
writer: "",
title: "",
body: "",
});
// 3. 핸들러 로직도 구현.
const handler = (e) => {
const { name, value } = e.target;
setName({
...tempName,
[name]: value,
});
};
// 1. 이 훅은 [ ] 을 반환하는데, 첫번째는 value, 두번째는 핸들러를 반환.
return [tempName, handler];
};
export default useInput;
input을 실제로 Form.jsx 에서 사용한 케이스
const Form = () => {
//커스텀 훅
const [title, onChangeTitleHandler] = useInput();
const [body, onChangeBodyHandler] = useInput();
const [writer, onChangeWriterHandler] = useInput();
// 이 다음부터는 값 받을 때 title, body, writer에서 받고 onChnageHandler도 on~ 에서 따로 받는다.
import React from "react";
import styled, { css } from "styled-components";
const Button = (props) => {
return (
<StButton {...props} disabled={props.disabled}>
{props.children}
{/* 부모에서 자식꺼를 쓸 수 있는 것
부모 :
<>
<자식/>
</>
*/}
</StButton>
);
};
export default Button;
const StButton = styled.button`
border: 1px solid gray;
background-color: #fff;
height: 46px;
border-radius: 8px;
background-color: ${({ bgColor, disabled }) => (disabled ? "#ddd" : bgColor)};
cursor: pointer;
${({ size }) => {
switch (size) {
case "large":
return css`
width: 100%;
`;
case "medium":
return css`
width: 80px;
`;
case "small":
return css`
width: 30px;
height: 30px !important;
`;
default:
return css`
width: 120px;
`;
}
}}
`;
이후 모든 버튼이 들어간 곳에 Button 을 상속시켜주면 사용이 가능하다.