• 카테고리

    질문 & 답변
  • 세부 분야

    프론트엔드

  • 해결 여부

    미해결

질문있습니다!

22.03.24 19:42 작성 조회수 155

0

안녕하세요 제로초님.

 

3-11강을 수강하던중 의문이 생겼습니다.

1. 만약 try컴포넌트에 memo를 사용하게 되면 숫자를 입력할때는 부모컴포넌트인  NumberBaseball에서 onChangeInput 함수가 실행되어 value state만 변경되어서 자식컴포넌트인 try컴포넌트는 리렌더링이 되자않는것은 이해했습니다. 

 

그러나 숫자를 입력하고 입력버튼을 눌러 onSubmitForm함수가 실행되게 되면 tries state 배열에 데이터가 추가되고 try컴포넌트에 props인 tryInfo props를 넘겨주잖아요? 이때 tries state배열이 변경되었는데 왜 자식컴포넌트인 try를 리렌더링이 되지 않는지 궁금합니다!

입력버튼을 눌렀을 때는 tries의 state가 변하고 props를 넘겨주니 자식컴포넌트인 try 컴포넌트가 한번 렌더링 되어야 하는거 아닌가요?..

 

밑에는 전체 코드입니다!

 


const NumberBaseball = () => {
  const [answer, setAnswer] = useState(getNumbers());
  const [value, setValue] = useState("");
  const [result, setResult] = useState("");
  const [tries, setTries] = useState([]);
  const inputEl = useRef(null);

  const onSubmitForm = useCallback(
    (e) => {
      e.preventDefault();
      if (value === answer.join("")) {
        setTries((t) => [
          ...t,
          {
            try: value,
            result: "홈런!",
          },
        ]);
        setResult("홈런!");
        alert("게임을 다시 실행합니다.");
        setValue("");
        setAnswer(getNumbers());
        setTries([]);
        inputEl.current.focus();
      } else {
        const answerArray = value.split("").map((v) => parseInt(v));
        let strike = 0;
        let ball = 0;
        if (tries.length >= 9) {
          setResult(`10번 넘게 틀려서 실패! 답은 ${answer.join(",")}였습니다!`); // state set은 비동기
          alert("게임을 다시 시작합니다.");
          setValue("");
          setAnswer(getNumbers());
          setTries([]);
          inputEl.current.focus();
        } else {
          console.log("답은", answer.join(""));
          for (let i = 0; i < 4; i += 1) {
            if (answerArray[i] === answer[i]) {
              console.log("strike", answerArray[i], answer[i]);
              strike += 1;
            } else if (answer.includes(answerArray[i])) {
              console.log(
                "ball",
                answerArray[i],
                answer.indexOf(answerArray[i])
              );
              ball += 1;
            }
          }
          setTries((t) => [
            ...t,
            {
              try: value,
              result: `${strike} 스트라이크, ${ball} 볼입니다.`,
            },
          ]);
          setValue("");
          inputEl.current.focus();
        }
      }
    },
    [value, answer]
  );

  const onChangeInput = useCallback((e) => setValue(e.target.value), []);

  return (
    <>
      <h1>{result}</h1>
      <form onSubmit={onSubmitForm}>
        <input
          ref={inputEl}
          maxLength={4}
          value={value}
          onChange={onChangeInput}
        />
        <button>입력!</button>
      </form>
      <div>시도: {tries.length}</div>
      <ul>
        {tries.map((v, i) => (
          <Try key={`${i + 1}차 시도 : ${v.try}`} tryInfo={v} />
        ))}
      </ul>
    </>
  );
};

export default NumberBaseball;
 
 
try.js
 
 
import React, { memo } from 'react';

const Try = memo(({tryInfo}) => {
  return (
    <li>
      <div>{tryInfo.try}</div>
      <div>{tryInfo.result}</div>
    </li>
  );
});

export default Try;

답변 1

답변을 작성해보세요.

0

tries의 값은 새로운 객체 하나가 생긴 것 빼고는 다른 객체들은 바뀌지 않았습니다. 거기다 memo로 감쌌으므로 부모가 리렌더링되더라도 자식은 props가 같으므로 리렌더링되지 않습니다.

Jack님의 프로필

Jack

질문자

2022.03.25

아... 제가 잘못이해한것 같습니다. 

그러면 tries state에 배열에 객체가 하나 추가 혹은 제거 되더라도 state가 추가 혹은 제거되는 것일 뿐 tries state가 변경되는 것은 아니어서 리렌더링이 일어나지 않는다는 말씀이시죠? (Memo도 사용했기 때문)

 

제가 이해한게 맞나요?...

tries state가 변경돼서 리렌더링은 일어나고요. 다만 자식 Try 캄포넌트는 리렌더링되지 않게 저희가 장치했으니 안일어나는겁니다.