ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 230113 30분 TIL forEach의 return
    하루 30분 TIL 2023. 1. 13. 14:32

    1. forEach 안에서 return/ breack 처리 ?! 

     상황

    아래의 코드를 리팩터링 하고자 했다. 

      useEffect(() => {
        if (!Object.keys(QUIZ_TASTE_DESCRIPTION).find((key: string) => title?.includes(key))) {
          return setTasteData(initialTasteData);
        }
    
        for (const [key, value] of Object.entries(QUIZ_TASTE_DESCRIPTION)) {
          if (title?.includes(key)) {
            setTasteData(value);
          }
        }
      }, [title]);

    QUIZ_TASTE_DESCRIPTION을 순회하는건 데 두 번씩이나 loop 할 필요 있을까? 한번으로 되지 않을까 라는 의문에서 시작됐다. 

    forEach문으로 조회시 가능하지 않을까 라는 생각이 들어 시도해 보았다.

     

      useEffect(() => {
        const QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY = Object.keys(QUIZ_TASTE_DESCRIPTION);
    
        const handleTasteData = (taste: string, index: number) => {
          if (title?.includes(taste)) {
            console.log('@@here!');
            return setTasteData(QUIZ_TASTE_DESCRIPTION[taste]);
          }
    
          if (index + 1 === QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY.length) {
            console.log('@@here2!');
            return setTasteData(initialTasteData);
          }
        };
    
        QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY.forEach(handleTasteData);
      }, [title]);

    의도한 건 includes 조건이 걸렸을 때 멈추고 마지막 index에서 tasteData를 initalTasteData로 리셋시키는 것이었다.

    하지만 의도와 달리 if문에서 조건이 걸리더라고 멈추지 않았고 tasteData가 initalTasteData로 리셋이 됐다.

     

     

    그래서 forEach 메소드가 얼리 리턴이 되는 줄 알고 그렇게 썼던 것 같은데 작동이 되지 않아 찾아봤다

     

    아래 코드를 보자 

     const arr = [1,2,3,4,5];
     
     arr.forEach((value) => {
     	if(value == 3) return;
        console.log(value);
        });
      // 기대 실제
      // 1    1
      // 2    2
      // 3    4
      //      5

     

     

    기대한 바는 3에서 멈추는 것인데 4, 5까지 나오는 것을 알 수 있다.

     

    아 생각해보니 이전에 썼을 때 해당 차수(index)에서 리턴 시키고 싶을 때 사용을 했구나! 기억이 났다.

     

    그렇다면 위의 경우 어떻게 해야할 까?

     

    for - of를 쓴다면 ?

     

        for(const taste of Object.keys(QUIZ_TASTE_DESCRIPTION)) {
            if (title?.includes(taste)) {
              setTasteData(QUIZ_TASTE_DESCRIPTION[taste]);
              break;
            }
            setTasteData(initialTasteData);
        }

     

    이렇게 쓸 때의 문제는 얼리 break 되지 않은 이상 setTasteData가 매번 실행되어 리렌더링이 계속될 것이다.

     

    그렇다면 if문에서 만났을때 조기 breack도 되면서 마지막 차수일 때만 가능하게 하는 유일한 방법은 for문 밖에 없다!

     

        const QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY = Object.keys(QUIZ_TASTE_DESCRIPTION);
    
        for (let i = 0; i < QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY.length; i++) {
          if (title?.includes(QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY[i])) {
            setTasteData(QUIZ_TASTE_DESCRIPTION[QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY[i]]);
            break;
          }
    
          if (i + 1 === QUIZ_TASTE_DESCRIPTION_KEYS_ARRAY.length) {
            setTasteData(initialTasteData);
          }
        }

    의도했던 대로 동작을 한다! 

     

    하지만 효율성을 위해 더 어려운 코드가 된 느낌을 지울 수 없다.... ㅠ 

    그래서 처음의 코드로 다시 해야할 것 같다 

     

    라고 생각을 해서 동료와 얘기를 해보니  for of문 안의 조건문 안에서 return을 쓰면 해당 loop 뿐 아니라 밑의 코드까지 가지 않고 return이 된다고 한다. 

     

      useEffect(() => {
        for (const [key, value] of Object.entries(QUIZ_TASTE_DESCRIPTION)) {
          if (title?.includes(key)) {
            setTasteData(value);
            return;
          }
        }
    
        setTasteData(initialTasteData);
      }, [title]);

    오호 훨씬 간단해졌다!!!

     

    오늘의 결론

     

    1. forEach 안에서 return이 되지 않는다. 

    2. for - of 문 안에서 break시 loop만 종료되고 return 시 일반 return 처럼 벗어날 수 있다. 

    '하루 30분 TIL' 카테고리의 다른 글

    230209 30분 TIL  (0) 2023.02.10
    230116 30분 TIL (Proxy)  (0) 2023.01.16
    2301112 30분 TIL (a태그 noopener noreferrer / SOLID)  (0) 2023.01.13
    221220 TIL(useRef)  (0) 2022.12.20
    221214 TIL(useImperativeHandler)  (0) 2022.12.14

    댓글

Designed by Tistory.