React Native 상태 관리 최적화: Optimistic UI Update 패턴 적용하기

oversleep·2025년 2월 16일
0

app-development

목록 보기
10/38
post-thumbnail

들어가며

이전 포스팅에서 다룬 매치 삭제 기능을 최적화해보았습니다.
특히 불필요한 서버 요청을 줄이고 사용자 경험을 개선하는 방향으로 리팩토링을 진행했습니다.

기존 코드의 문제점

const handleDelete = async (matchId: number) => {
  try {
    const response = await axiosInstance.delete(`/matches/${matchId}`);
    if (response.status === 200 || response.status === 204) {
      Alert.alert("성공", "매치가 삭제되었습니다");
      await loadParticipations(); // 불필요한 서버 요청
      onUpdate?.();
    }
  } catch (error) {
    // ... 에러 처리
  }
};

주요 문제:
1. 삭제 성공 후 전체 목록을 다시 로딩
2. 불필요한 네트워크 요청 발생
3. UI 업데이트가 서버 응답을 기다려야 함

Optimistic UI Update 패턴 적용

// 로컬 상태 추가
const [localParticipations, setLocalParticipations] = useState(participations);

// props 변경 시 동기화
useEffect(() => {
  setLocalParticipations(participations);
}, [participations]);

const handleDelete = async (matchId: number) => {
  try {
    Alert.alert("매치 삭제", "정말로 이 매치를 삭제하시겠습니까?", [
      {
        text: "취소",
        style: "cancel",
      },
      {
        text: "삭제",
        style: "destructive",
        onPress: async () => {
          // 먼저 로컬 상태 업데이트
          setLocalParticipations(prev => 
            prev.filter(item => item.match.id !== matchId)
          );

          try {
            const response = await axiosInstance.delete(`/matches/${matchId}`);
            if (response.status === 200 || response.status === 204) {
              Alert.alert("성공", "매치가 삭제되었습니다");
              onUpdate?.();
            }
          } catch (error) {
            // 실패 시 원상 복구 로직 추가 가능
            setLocalParticipations(participations);
            Alert.alert("오류", "매치 삭제 중 오류가 발생했습니다");
          }
        },
      },
    ]);
  } catch (error) {
    Alert.alert("오류", "매치 삭제 중 오류가 발생했습니다");
  }
};

개선된 점

  1. 성능 최적화

    • 불필요한 서버 요청 제거
    • 네트워크 트래픽 감소
    • 서버 부하 감소
  2. 사용자 경험 향상

    • 즉각적인 UI 응답
    • 더 빠른 피드백
    • 자연스러운 상태 전환
  3. 코드 품질 향상

    • 명확한 상태 관리
    • 에러 처리 용이
    • 유지보수성 증가

구현 시 고려사항

  1. 상태 동기화

    useEffect(() => {
      setLocalParticipations(participations);
    }, [participations]);
    • props와 로컬 상태의 동기화 유지
    • 외부 데이터 변경 반영
  2. 에러 처리

    catch (error) {
      // 실패 시 원상 복구
      setLocalParticipations(participations);
      Alert.alert("오류", "매치 삭제 중 오류가 발생했습니다");
    }
    • 실패 시 롤백 처리
    • 사용자에게 적절한 피드백 제공
  3. 성능 모니터링

    • 메모리 사용량 관찰
    • 불필요한 리렌더링 체크
    • 상태 업데이트 최적화
profile
궁금한 것, 했던 것, 시행착오 그리고 기억하고 싶은 것들을 기록합니다.

0개의 댓글