React에서 useEffect를 사용하여 상태를 업데이트할 때 무한 루프를 방지하는 방법

React에서 useEffect로 무한 반복을 피하는 방법 React 프로그래밍에서 상태를 업데이트할 때 무한 반복을 처리하는 것은 흔한 문제입니다. 이는 useEffect 훅의 의존성이 제대로 지정되지 않을 때 발생할 수 있습니다. 이번 블로그 포스트에서는 상태 업데이트로 인해 무한 …

title_thumbnail(React에서 useEffect를 사용하여 상태를 업데이트할 때 무한 루프를 방지하는 방법 - Todo 항목 정렬에 대한 문제 해결 팁)

React에서 useEffect로 무한 반복을 피하는 방법

React 프로그래밍에서 상태를 업데이트할 때 무한 반복을 처리하는 것은 흔한 문제입니다. 이는 useEffect 훅의 의존성이 제대로 지정되지 않을 때 발생할 수 있습니다. 이번 블로그 포스트에서는 상태 업데이트로 인해 무한 반복이 발생하는 시나리오를 살펴보고 이 문제에 대한 해결책을 논의하겠습니다.

문제: ESLint에 의해 유발된 무한 반복

React 애플리케이션에서 할 일 목록을 가지고 있고 사용자가 제목 또는 우선순위 등을 기준으로 목록을 정렬할 수 있도록하려고 합시다. 할 일 목록과 현재 선택된 정렬 키를 나타내는 두 개의 상태 변수 todossortKey를 가지고 있습니다.

const [todos, setTodos] = useState([]);
const [sortKey, setSortKey] = useState('title');

const setSortedTodos = useCallback((data) => {
  const cloned = data.slice(0);

  const sorted = cloned.sort((a, b) => {
    const v1 = a[sortKey].toLowerCase();
    const v2 = b[sortKey].toLowerCase();

    if (v1 < v2) {
      return -1;
    }

    if (v1 > v2) {
      return 1;
    }

    return 0;
  });

  setTodos(sorted);
}, [sortKey]);

useEffect(() => {
    setSortedTodos(todos);
}, [setSortedTodos]);

위의 코드는 예상대로 동작하는 것처럼 보이지만 ESLint에서 useEffect의 의존성 배열에 todos를 추가하도록 요구합니다. 이 조언에 따르면 무한 반복이 발생합니다.

해결책: useEffect 대신 useMemo 사용하기

무한 반복을 방지하기 위해 useEffect 대신 useMemo 훅을 사용할 수 있습니다. 할 일 목록을 정렬한 배열을 메모이징함으로써 정렬 키 또는 할 일 목록 배열이 변경될 때마다 이 배열을 얻을 수 있습니다.

const sortedTodos = useMemo(() => {
  return Array.from(todos).sort((a, b) => {
    const v1 = a[sortKey].toLowerCase();
    const v2 = b[sortKey].toLowerCase();

    if (v1 < v2) {
      return -1;
    }

    if (v1 > v2) {
      return 1;
    }

    return 0;
  });
}, [sortKey, todos]);

이제 단순히 컴포넌트의 렌더링 로직에서 sortedTodos 배열을 사용하여 정렬된 할 일 목록을 표시할 수 있습니다. 이 접근 방식은 정렬된 배열이 필요한 경우에만 계산되므로 불필요한 다시 렌더링을 방지하고 무한 반복의 가능성을 피할 수 있습니다.

최종 구현

const { useState, useCallback, useMemo } = React;

const exampleToDos = [
    {title: "This", priority: "1 - high", text: "Do this"},
    {title: "That", priority: "1 - high", text: "Do that"},
    {title: "The Other", priority: "2 - medium", text: "Do the other"},
];

function Example() {
  const [sortKey, setSortKey] = useState('title');
  const [todos, setTodos] = useState(exampleToDos);

  const sortedTodos = useMemo(() => {
    return Array.from(todos).sort((a, b) => {
      const v1 = a[sortKey].toLowerCase();
      const v2 = b[sortKey].toLowerCase();

      if (v1 < v2) {
        return -1;
      }

      if (v1 > v2) {
        return 1;
      }

      return 0;
    });
  }, [sortKey, todos]);

  const sortByChange = useCallback((e) => {
    setSortKey(e.target.value);
  }, []);

  return (
    <div>
      정렬 기준: 
      <select onChange={sortByChange}>
        <option selected={sortKey === "title"} value="title">제목</option>
        <option selected={sortKey === "priority"} value="priority">우선순위</option>
      </select>
      {sortedTodos.map(({ text, title, priority }) => (
        <div className="todo">
          <h4>{title} <span className="priority">{priority}</span></h4>
          <div>{text}</div>
        </div>
      ))}
    </div>
  );
}

ReactDOM.render(<Example />, document.getElementById("root"));

축하합니다! useEffect 대신 useMemo를 사용하여 React에서 상태를 업데이트하는 무한 반복 문제를 성공적으로 해결했습니다. 이제 성능이나 불필요한 다시 렌더링을 걱정하지 않고 할 일 목록을 올바르게 정렬할 수 있습니다.

상태 및 해당 의존성에서 값을 유도해야 하는 경우 useMemo를 사용하고 데이터를 가져오거나 이벤트에 대해 구독하는 것과 같은 부작용에는 useEffect를 사용하는 것을 기억하세요. 즐거운 코딩하세요!

참고 자료 : 

reactjs

Leave a Comment