점 표기법으로 Firestore의 중첩 필드 업데이트

문맥



React + Rirebase(Firestore as db) 프로젝트에서 확장된 설문지를 개발하는 동안 객체에 중첩된 필드에 쓰는 방법을 찾는 데 직면했습니다.

이러한 확장된 질문은 실시간 업데이트를 수신하고 데이터를 수정할 때 데이터를 표시할 수 있도록 사용자 프로필에 대한 리스너가 있는 대시보드 스타일 페이지에 있었습니다. 리스너가 있었기 때문에 다시 렌더링하는 구성 요소의 수를 제한하기 위해 가능한 가장 작은 쓰기 작업을 수행하려고 했습니다.

수정하려는 질문은 다음과 같이 구성되었습니다.

{
  "Questions":{
    "Q11":{
      "Paper":{
        "EF":0.2811,
        "amount":5002,
        "name":"Paper",
      },
      "Furniture":{
        "EF":0.3677,
        "amount":400,
        "name":"Furniture"
      }
    }
  }
}


변경할 필드는 amount 필드였습니다. 페이지에서 질문은 입력으로 제시되어 필드가 변경되자마자 onChange 이벤트를 발생시킵니다. 이 경우에 이상적이지만 다시 작성을 피하기 위해 가능한 한 최소한으로 작성하는 것이 더 필요합니다. -렌더링.

초기 구성 요소:

const ExtendedQuestions = (props) => {
  const { Q11 } = props;
  const [loading, setLoading] = React.useState(null);

  return (
    <React.Fragment>
      {Q11.map((question, i) => {
        const { name, EF, amount } = question;
        return (
          <input
            key={`ExtendedField_${i}`}
            inline
            label={name}
            type="number"
            name={name}
            ef={EF}
            value={amount}
            loading={name === loading}
            min={0}
            max={100000}
            step={1}
          />
        );
      })}
    </React.Fragment>
  );
};


초기 발견



양식의 onChange 이벤트가 답변을 수정하는 사용자 프로필에 대한 쓰기를 트리거한다는 목표를 염두에 두고 솔루션을 찾기 위해 Firebase 문서에 뛰어 들었습니다. 문서를 읽는 동안 "dot notation"을 사용하여 중첩된 개체에 쓰기 작업을 수행하는 방법에 대한 작은 섹션을 발견했습니다. 이 솔루션은 이상적인 것처럼 보였지만 문서에서는 "점 표기법"이 문자열 형식으로 지정되어야 하는 것 같았습니다. 내 구성 요소가 단순하게 작성되었다는 점을 고려할 때 첫 번째 생각은 각 입력에 대한 함수를 작성해야 한다는 것이었습니다.

해결책



답을 찾는 데 큰 지장을 주지 않고 "점 표기법"에 대한 문자열을 동적으로 설정하는 방법을 검색한 후 대괄호 표기법(예: [pathInDotNotation])을 사용하여 개체를 만들고 결과를 테스트하기만 하면 된다고 생각했습니다.

다음과 같이 onChange 기능을 작성했습니다.

const handleChange = (e, data) => {
    const { name, ef, value } = data;
    setLoading(name);
    firebase
      .collection("users")
      .doc(`${authUser}`)
      .update({
        [`Questions.Q11.${name}`]: {
          text: name,
          amount: Number(value),
          EF: Number(ef),
        },
      })
      .then(() => {
        setLoading(null);
      })
      .catch((error) => {
        console.error("Error updating document: ", error);
      });
  };


그리고 당신은 그것을 몰랐을까요? 그것은 효과가 있었습니다!

내 전체 구성 요소는 다음과 같습니다.

const ExtendedQuestions = (props) => {
  const { Q11 } = props;
  const [loading, setLoading] = React.useState(null);

  const handleChange = (e, data) => {
    const { name, ef, value } = data;
    setLoading(name);
    firebase
      .collection("users")
      .doc(`${authUser}`)
      .update({
        [`Questions.Q11.${name}`]: {
          text: name,
          amount: Number(value),
          EF: Number(ef),
        },
      })
      .then(() => {
        setLoading(null);
      })
      .catch((error) => {
        console.error("Error updating document: ", error);
      });
  };

  return (
    <React.Fragment>
      {Q11.map((question, i) => {
        const { name, EF, amount } = question;
        return (
          <input
            key={`ExtendedField_${i}`}
            inline
            label={name}
            type="number"
            name={name}
            ef={EF}
            value={amount}
            loading={name === loading}
            min={0}
            max={100000}
            onChange={handleChange}
            step={1}
          />
        );
      })}
    </React.Fragment>
  );
};



내 구성 요소가 이제 변경이 필요한 필드에만 쓸 수 있었기 때문에 이것은 훌륭했습니다. 또한 지도 기능을 사용하여 모든 질문을 키로 렌더링하므로 변경된 실제 입력만 대상으로 하여 재렌더링을 최소화할 수 있었습니다.

읽어 주셔서 감사합니다! 피드백을 주시면 감사하겠습니다. :)

좋은 웹페이지 즐겨찾기