[React] Apexcharts Real-time Line chart

이경은·2023년 3월 14일

들어가기

AWS AppSync GraphQL의 Subscription을 사용해서 데이터가 실시간으로 들어오면 기존 배열에 새로운 값을 추가해서 실시간 차트를 구현했다.

How to use

Apexcharts line chart 변수 형태

  • series
    • y 축의 값을 가지고 있는 부분. 객체 배열.
    • [ { name: “humidity”, data: [ 10, 20, 30 ] }, { name: “humidity”, data: [ 10, 20, 30 ] } ]
  • categories
    • x 축의 값을 가지고 있는 부분. 시간 배열
    • [ 1678230384, 1678230384, 1678230384 ]

코드

  • useEffect를 통해서 event data를 subscription 한다.
  • 이벤트가 발생하면 next 안에 있는 로직이 실행되며, newValue라는 변수를 업데이트 시킨다.
  • 이벤트 데이터 중에서 modeledData가 값이 없는 경우가 아닐 때만 업데이트 시킨다.
  • newValue가 업데이트 되면, useEffect 훅을 통해서 다른 로직이 실행되도록 했다.
const [series, setSeries] = useState([]);
const [categories, setCategories] = useState([]);

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

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

  return () => {
    subscription.unsubscribe();
  };

}, []);
  • 아래 코드는 newValue가 변경되면 동작하는 useEffect()함수
  • useDidMountEffect는 첫 렌더링 시에 동작하지 않고, 배열 안의 변수가 변경될 때만 실행되도록 하는 useEffect의 custom hook이다.
useDidMountEffect(() => {
	// newValue의 modeledData를 string에서 json 형태로 parsing
  const newData = JSON.parse(newValue.modeledData);

	// 기존 카테고리에 newValue의 createdTime을 milisecond 단위로 변환해서 추가
	// 새로운 카테고리 배열 생성
  const newCategory = [...categories];
  newCategory.push(newValue.createdTime * 1000);

	// json 형태의 newData에서 key, value를 분리한다
  const keyArr = Object.keys(newData);
  const valueArr = Object.values(newData);

  let newSeries = [];

	// series의 length 가 0이면 기존에 값이 없다는 뜻.
	// series 형태를 만들어서 넣어줘야 함.
  if (series.length === 0) {
    newSeries = keyArr.map((item, idx) => {
      const tempdata = { name: item, data: [valueArr[idx]] };
      return tempdata;
    });
  } else { // 기존 series 값이 있음
    const seriesArr = keyArr.map((item, idx) => {
      let tempSeries = {};
			// series에서 name이 key 값과 일치하는 항목이 있는지 확인
			// 없으면 undefined 반환
      tempSeries = series.find((e) => e.name === item);

			// name이 key값과 일치하면
      if (tempSeries !== undefined) {
				// data 배열에 value를 추가함
        tempSeries.data.push(valueArr[idx]);
      }
      return tempSeries;
    });

		// 위에서 tempSeries가 undefined로 나온 것들을 filtering
    newSeries = seriesArr.filter((e) => e !== undefined);
  }
  // console.log('new graph value', newSeries, newCategory);

  setSeries(newSeries);
  setCategories(newCategory);
}, [newValue]);
profile
Frontend Developer

0개의 댓글