[React] AppSync GraphQL Subscription 시에 setState 사용하기

이경은·2023년 3월 14일
0

❌ Error

문제가 발생한 부분은 AppSync의 GraphQL subscription을 통해서 새로운 값을 받고, 새로운 값을 기존 배열에 추가해서 배열을 변경하는 로직이었다.

새로운 값이 들어오면, 기존 배열을 복사한 배열을 생성하고 복사한 배열에 새로운 값을 넣고, setState를 사용해서 배열 값을 변경하는 방식 사용했다.

⇒ 이렇게 하니 처음에는 잘 되는 것 같았지만, setState가 제대로 이뤄지지 않아 처음 한 두번은 제대로 실행되다가 그 후로는 subscribe 안의 코드가 반복해서 실행되며 배열이 제대로 업데이트 되지 않는 문제가 발생했다.

아래는 기존 코드

import { useEffect, useState } from 'react';

const [eventList, setEventList] = useState([]);

const deviceEventCreated = async () => {
  try {
    const subscription = await API.graphql(
      graphqlOperation(subscriptions.onCreateDeviceEvent, {
        deviceId: deviceId,
      })
    ).subscribe({
      next: ({ provider, value }) => {
        console.log('value', value.data.onCreateDeviceEvent);
        // 배열을 복사하고, 바로 배열을 변경했다
        const arr = [...eventList];
        arr.unshift(value.data.onCreateDeviceEvent);
        console.log('new event list', arr);
        setEventList(arr);
      },
      error: (error) => console.log('Error: ', error),
    });

    subscription.unsubscribe();
  } catch (error) {
    console.log('[deviceEventCreated]', error);
  }
};

useEffect(() => {
  deviceEventCreated();
});

✅ Solution

newValue라는 변수를 추가해주었다. subscription 이벤트가 발생하면 setNewValue로 값을 업데이트 시켜주고, newValue가 변경될 때 eventList를 업데이트 시켜주었다.

useDidMountEffect는 커스텀 훅으로, 최초 실행 시에 함수가 실행되지 않고 배열 안의 변수가 변경 될 때에만 실행되도록 넣었다.

import { useCallback, useEffect, useState } from 'react';
import useDidMountEffect from '../../../hooks/useDidMountEffect';

const [newValue, setNewValue] = useState({});
const [eventList, setEventList] = useState([]);

useEffect(() => {
  const subscription = API.graphql(
    graphqlOperation(subscriptions.onCreateDeviceEvent, {
      deviceId: deviceId,
    })
  ).subscribe({
    next: (data) => {
      // console.log('new data', data.value.data.onCreateDeviceEvent);
      setNewValue(data.value.data.onCreateDeviceEvent);
    },
  });

  return () => {
    subscription.unsubscribe();
  };
  // eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useDidMountEffect(() => {
  const arr = [...eventList];
  arr.unshift(newValue);
  console.log('arr');
  setEventList(arr);
}, [newValue]);
profile
Web Developer

0개의 댓글