Recoil로 사용자 답변 전역 상태로 저장하기

y·2024년 2월 26일
1

💬 TIL

목록 보기
5/10
post-thumbnail
post-custom-banner

답변 폼을 만들어보자

사용자가 답변을 textarea 영역에 적으면 이 답변을 다른 페이지에 답변을 하고 수정하려고 돌아왔을 때도 유지된 상태로 보여줘야 했다. 또 사용자가 각 페이지마다 답변한 내용을 한꺼번에 데이터베이스에 저장하기 위해서는 전역 상태로 관리하는게 편하기 때문에 Recoil을 이용해 사용자의 답변을 저장하기로 했다.

❶ 키워드 저장하기

✔️ 선택한 키워드에 대한 답변

이전 페이지에서 사용자가 자신이 답변하고 싶은 키워드를 누르면, 그 키워드에 대한 답변을 작성한다.

위 페이지에서 선택했던 키워드도 전역 상태로 저장하고, 해당 페이지에 왔을
때는 사용자가 선택한 키워드에 대한 답을 쓸 수 있는 컴포넌트를 보여준다.

사용자가 선택한 키워드 저장하기

① 답변에 대한 전역 상태 정의

export const answerState = atom({
  key: 'otherAnswerState',
  default: {
    name: '', 
    strength: [], // 사용자가 선택한 키워드 저장
    strengthReview: { // 키워드 선택 이유 답변 저장
    /* 
      keyword: review_description,
    */
    }, 
  },
});

strengthReview[키워드]로 해당 키워드에 대한 답변을 불러올 수 있도록 객체 형태로 정의했다.

② 키워드 저장

const [answer, setAnswer] = useRecoilState(answerState);

const clickChip = (chip) => {
  let update = [...answer.strength]
  if (update.includes(chip)) { // 칩 선택 취소
    setAnswer({
      ...answer, strength: [...update.filter(item => item !== chip)]
    })
  } else if (update.includes(chip) === false) { // 칩 선택
      if (answer.strength.length < 3) {
        update.push(chip);
        setAnswer({
          ...answer, strength: update
        })
      }
   }

사용자가 키워드 칩을 누를 때마다 동작하는 함수이다. 해당 chip을 누르면 strength 배열에 이미 있는 경우에는 선택이 취소되지만, chip이 배열에 없는 경우에는 칩을 strength 배열에 추가한다. (3개까지만 선택 가능하므로 길이가 3 이하일 때만 배열에 추가하도록 했다.)

배열 추가 혹은 삭제 시에는 setAnswer를 이용해준다. setAnswer({...answer, strength: update}) 이런 식으로 써주면 된다.

  • ...answer ⇨ 이전에 전역 상태에 저장된 값을 불러와서 복사해준다.
  • strength: update ⇨ 우리가 변경해줄 값은 answerState에서 strength 값이므로, strength 값을 변경 원하는 update 값으로 변경해준다.

위와 같이 저장하면, 선택한 키워드가 strength 배열에 저장된다.


❷ 키워드별로 답변 저장하기

사용자가 선택한 키워드가 최대 3개까지인데, 각 키워드에 대한 답을 저장해두어야한다. 위에서 전역 상태를 정의할 때, 키워드는 strength 배열에 저장하기로 했고 선택한 키워드에 대한 답변은 strengthReview에 저장하기로 했다.

strength 상태 관리: 배열 형태로 저장하고 삭제하는 업데이트 방법은 ❶번에서 설명했다.

객체 상태 저장하기

각 키워드에 대한 답은 키워드 이름: 해당 키워드에 대한 답으로 객체로 저장된다.

전체 코드

function AnswerBox(props) {
  const [answer, setAnswer] = useRecoilState(answerState);
  const chipTitle = "키워드1";
  const [inputText, setInputText] = useState(answer.strengthReview[chipTitle] || "");

  /* 사용자가 textarea에 입력할 때마다 값 업데이트 */
  const handleChange = (e) => {
    setInputText(e.target.value);
    setAnswer({
      ...answer,
      strengthReview: {
        ...answer.strengthReview,
        [chipTitle]: e.target.value
      },
    });
  };
  
  return (
    <>
      <textarea
        value={inputText}
        placeholder="민지님과 OO 프로젝트를 진행할 때 oo아이디어에 관해 팀원의 의견을 수렴하는 과정에서 이야기를 경청하는 모습이 인상 깊었어요 :)"
        onChange={handleChange}
      />
    </>
  )
}

textarea 영역에 사용자가 글을 작성하게 되면 onChange에 정의된 함수인 handleChange가 동작한다.
handleChange에서는 사용자가 입력한 값을 inputText에 저장하고, 전역 상태에 strengthReview에 사용자가 입력한 값을 업데이트 해준다.

strengthReview는 배열이 아닌 객체이므로 저장할 때 다음과 같이 저장해준다.

setAnswer({
  ...answer,
  strengthReview: {
    ...answer.strengthReview,
   [chipTitle]: e.target.value
  },
});

chipTitle은 사용자가 선택한 키워드로 이 키워드에 대한 사용자 답변을 저장한다.

💡 [chipTitle]로 써준 이유
객체 안에서 변수 chipTitle을 쓰려면 대괄호를 사용해주어야 하기 때문이다.

결과

선택한 키워드가 저장되어 다음 페이지에서 보여지고, 적은 답변도 페이지를 이동하고 돌아온 후에도 유지되는 것을 볼 수 있다.

profile
hiyunn.contact@gmail.com
post-custom-banner

0개의 댓글