๐ ๋ฐฑ์๋์์ ์ง๋ฌธ ๋ฐ์ดํฐ ์์ ๋ต๋ณ ๋ฐ์ดํฐ๊ฐ ํฌํจ๋ ํํ๋ก ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ธฐ๋ก ํ๋ค.
๐๐ฝ ๊ฐ ํ์ด์ง์ ํด๋นํ๋ ์ง๋ฌธ(+๋ต๋ณ) ๋ฐ์ดํฐ ๋ฐ์์ค๊ธฐ
๐๐ฝ ๋ต๋ณ ๋ถ๋ถ์ ์ง๋ฌธ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์์ ๊ฐ๊ณตํด์ ์ฐ๋ ๊ฑธ๋ก..!
๋ฐ์ดํฐ ํํ
{ "questions": [ { "id": 1, "questionId": 1, "title": "๐ Suggestion for Automatically Match Data in MysQL", "content": "๐ I have limited access to the MySQL database, I just can see a view called customer contains customer_id, name, and their location", "question_tag": [ "python", "mysql", "database", "jupyter-notebook" ], "totalRecommend": 3, "createdAt": "Dec 12 at 6:48", "member_id": "Arthur", "answers": [ { "answerId": 1, "content": "๐ฆ This is a very stacked question with lots of steps needed to achieve what you want. So let's dive straight in! First, we should read the data frames from your (uncleaned) customer database and your location database", "recommend": 1, "createdAt": "Dec 15 at 12:06", "choose": false, "member_id": "Luke", "questionId": 1 }, { "answerId": 2, "content": "๐ฅ I don't know if I understood correctly here.. [...] I mean if in the raw data there is punctuation or number or typo, it will automatically clean [...] You need some sort of validation method here, you cannot achieve that directly on the database, you need to handle it in your logic before the rows insertion. In these cases, the best solution is to prepare a picklist (multiple choice) from which end users can choose the right values. A free text input will always be error prone.If the multiple choiceis not an applicable solution in your case, then you need to put in place a list of validation rules but you need to think how to prevent every possible issue.", "recommend": 4, "createdAt": "Dec 15 at 12:06", "choose": false, "member_id": "Denis B.", "questionId": 1 } ] }, ...
DetailPage.js
DetailPage.js
์์ ๋ฐ์ดํฐ ๋ฐ์์์ ํ์ํ ์ปดํฌ๋ํธ์ props๋ก ๋๊ฒจ์ค๋ค.useEffect(() => { async function request() { const response = await axios.get( // ํด๋น ์ง๋ฌธ ๋ฐ์ดํฐ ๋ฐ์์ค๊ธฐ `${process.env.REACT_APP_API_URL}/api/questions/${questionId}`); const { data } = response; console.log(data); setQuestionData(data); } request(); }, []); ... return ( <> {questionData && ( <DetailContainer> <Title data={questionData} /> // ํด๋น ์ง๋ฌธ ๋ฐ์ดํฐ props๋ก ๋๊ฒจ์ฃผ๊ธฐ <hr /> <ContentsAndSideBox> <ContentsContainer> <Contents data={questionData} /> //ํด๋น ์ง๋ฌธ ๋ฐ์ดํฐ props๋ก ๋๊ฒจ์ฃผ๊ธฐ </ContentsContainer> <SideBox> <QuestionsSub /> </SideBox> </ContentsAndSideBox> </DetailContainer> )} </> ); }
Delete
๋ฒํผ ๋๋ฅด๋ฉด ๋ต๋ณ ์ง์์ง๋๋ก ํ๊ธฐ
AnswerList.js
export default function AnswerList({ isMyQuestion, data }) { ... function handleAnswerDelete(e, answerId) { const newAnswerList = data.filter((el) => el.answerId !== answerId); // ํด๋น ๋ต๋ณ์ด ๋น ์ง ์๋ก์ด ๋ต๋ณ ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ e.preventDefault(); async function request() { await axios.patch( // patch ์์ฒญ ๋ณด๋ด๊ธฐ `${process.env.REACT_APP_API_URL}/api/questions/${questionId}`, { answers: newAnswerList } ); window.location.reload(); } request(); } ... return ( ... <button onClick={(e) => handleAnswerDelete<(e, answer.answerId)}className="menu">Delete</button>
newAnswerList
) ๋ง๋ค๊ธฐaxios.patch
์ ๋ ๋ฒ์งธ ์ธ์๋ก patchํ ๋ถ๋ถ์ ๊ฐ์ฒด ํํ๋ก ๋ฃ์ด์ฃผ๊ธฐanswers
ํญ๋ชฉ์ ๊ฐ์ ์๋ก ๋ง๋ newAnswerList
๋ก ๋ฐ๊พธ๋ ๊ฒ)AnswerSubmit.js
export default function AnswerSubmit({ data }) { const [answer, answerBind] = useInput(); // ์ปค์คํ ํ (useInput) ์ด์ฉ const newAnswer = { // ์ ๋ต๋ณ ๊ฐ์ฒด ๋ง๋ค๊ธฐ answerId: data.length + 1, content: answer, recommend: 0, createdAt: new Date().toLocaleDateString('ko-KR'), choose: false, member_id: 'Pika', questionId: questionId, }; const handleSubmit = (e) => { // SubmitBtn ํด๋ฆญ ์ ์คํ e.preventDefault(); async function request() { await axios.patch( `${process.env.REACT_APP_API_URL}/api/questions/${questionId}`, { answers: [...data, newAnswer] } ); window.location.reload(); } request(); }; ... return ( <div> <AnswerFormHeader>Your Answer</AnswerFormHeader> <form onSubmit={handleSubmit}> <Textarea required {...answerBind} placeholder=""></Textarea> <Guideline> Thanks for contributing an answer to Stack Overflow! <br /> ... <SubmitBtn>Post Your Answer</SubmitBtn> </form>
newAnswer
) ๋ง๋ค๊ธฐaxios.patch
์ ๋ ๋ฒ์งธ ์ธ์๋ก patchํ ๋ถ๋ถ์ ๊ฐ์ฒด ํํ๋ก ๋ฃ์ด์ฃผ๊ธฐanswers
ํญ๋ชฉ์ ๊ฐ(๋ฐฐ์ด)์ ์ ๋ต๋ณ(newAnswer
)์ ์์๋ก ์ถ๊ฐํ ๊ฒ)useInput.js
) ์ด์ฉuseInput.js
import { useState } from 'react'; const useInput = () => { const [inputValue, setInputValue] = useState(''); const bind = { value: inputValue, onChange: (e) => setInputValue(e.target.value), }; return [inputValue, bind]; }; export default useInput;
- ์ ๋ ฅ๋ ๊ฐ์ ๋ฐ์์ค๊ณ
- value๋ฅผ ์ ๋ ฅ๋ ๊ฐ์ผ๋ก ๋ง์ถฐ์ฃผ๋(= ์ ์ด ์ปดํฌ๋ํธ๋ก ๋ง๋๋) ์ปค์คํ ํ
Edit
๋ฒํผ ํด๋ฆญ ์ ๋ต๋ณ ์์ ํ์ด์ง๋ก ์ด๋<Link to={`/posts/${questionId}/edit/${answer.answerId}`}> <button className="menu">Edit</button> </Link>
editedAnswerList
)์ ์์ ๋ ๋ต๋ณ ๊ฐ์ฒด(editedAnswer
) ๋ง๋ค๊ธฐEditAnswerPage.js
export default function EditAnswerPage() { const [edited, editedBind] = useInput(); // ์ปค์คํ ํ (useInput ์ฌ์ฉ) const handleEditSubmit = (e, answerId) => { // SubmitBtn ํด๋ฆญ ์ ์คํ // ์์ ํ ๋ต๋ณ๋ง ๋บ ๋ต๋ณ ๋ฆฌ์คํธ ๋ง๋ค๊ธฐ const editedAnswerList = answerData.filter( (el) => el.answerId !== Number(answerId) ); // ์์ ๋ ๋ต๋ณ ๋ง๋ค๊ธฐ const editedAnswer = { answerId: Number(answerId), // params๋ก ๋ฐ์์ด content: edited, // useInput ์ด์ฉํด์ ๋ฐ์์ด recommend: answerData[answerId - 1].recommend, createdAt: answerData[answerId - 1].createdAt, choose: answerData[answerId - 1].choose, member_id: answerData[answerId - 1].member_id, questionId: Number(questionId), // params๋ก ๋ฐ์์ด }; e.preventDefault(); async function request() { await axios.patch( `${process.env.REACT_APP_API_URL}/questions/${questionId}`, { answers: [...editedAnswerList, editedAnswer] } ); navigate(`/questions/${questionId}`); } request(); }; return ( <> {answerData && ( ... <form onSubmit={(e) => handleEditSubmit(e, answerId)}> <Textarea required {...editedBind} placeholder={answerData[answerId - 1].content}></Textarea> ... </Guideline> <SubmitBtn>Save edits</SubmitBtn> </form>
placeholder
๋ก ํด๋น ๋ต๋ณ ๋ ์๊ฒ ํ๊ธฐexport default function EditAnswerPage() { const [answerData, setAnswerData] = useState(); // id ์์ผ๋ก ์ ๋ ฌ๋ answer ๋ฐ์ดํฐ ... useEffect(() => { async function request() { const response = await axios.get( // 1) ๋ต๋ณ ์ํ ์ง๋ฌธ ๋ฐ์ดํฐ ์ ์ฒด ๋ฐ์์ค๊ธฐ `${process.env.REACT_APP_API_URL}/questions/${questionId}`); const { data } = response; // 2) answer ๋ฐ์ดํฐ id ์์ผ๋ก ์ ๋ ฌ const sortedAnswerData = data.answers.sort(function (a, b) { if (a.answerId > b.answerId) { return 1; } if (a.answerId < b.answerId) { return -1; } return 0; }); setAnswerData(sortedAnswerData); } request(); }, []); ... return ( <Textarea required {...editedBind} placeholder={answerData[answerId - 1].content}></Textarea> // 3) placeholder๋ก ๋ณด์ฌ์ฃผ๊ธฐ