React-Native/[프로젝트] 택시 운행관리 기록장

[React-native CLI] RN에서 Realm 세팅 및 사용(구조 전면 교체)

개발조각 2024. 3. 19. 21:41
728x90
반응형

realm설정을 했었는 데 사용하다 보니 db을 열고 닫는 상황이 중복적으로 발생하다 보니 오류를 마주하게 되고

결국은 realm 구조를 새롭게 수정해보았습니다.

 

폴더구조


구조는 똑같은데 realm폴더에 recordRealmFunctions.ts를 추가했습니다.

 

realm 세팅


realm/schema.ts

// 운행기록 스키마
export const RecordSchema = {
  name: 'Record',
  properties: {
    date: 'string',
    card: 'int',
    cash: 'int', // 현금
    lpgInjectionVolume: 'int', // LPG 주입량
    lpgUnitPrice: 'int', // LPG 단가
    mileage: 'int', // 주행거리
    businessDistance: 'int', // 영업거리
    toll: 'int', // 통행료
    operatingAmount: 'int', // 영업금액
    lpgChargeAmount: 'int', // LPG 충전 금액
    fuelEfficiency: 'int', // 연비
    lpgUsage: 'int', // LPG 사용량
  },
  primaryKey: 'date',
};

 

realm/recordRealmFunctions.ts

import Realm from 'realm';

import {RecordSchema} from './schema';
import {RecordType} from '../types/types';

// Realm 데이터베이스 연결
const realm = new Realm({schema: [RecordSchema]});

// CREATE : 새로운 기록 추가
export const createRecord = (newData: RecordType) => {
  realm.write(() => {
    realm.create('Record', newData);
  });

  console.log('데이터가 생성되었습니다.');
};

// READ_All
export const readAllRecord = () => {
  return realm.objects<RecordType>('Record');
};

// READ : 선택한 날짜의 데이터
export const readSelectDateRecord = (selectDate: string) => {
  const selectDateData = realm
    .objects('Record')
    .filtered(`date = '${selectDate}'`)[0];

  return selectDateData;
};

// UPDATE
export const updateRecord = (newData: RecordType) => {
  const selectDateData = realm
    .objects('Record')
    .filtered(`date = '${newData.date}'`)[0];

  if (selectDateData) {
    realm.write(() => {
      selectDateData.card = newData.card;
      selectDateData.cash = newData.cash;
      selectDateData.lpgInjectionVolume = newData.lpgInjectionVolume;
      selectDateData.lpgUnitPrice = newData.lpgUnitPrice;
      selectDateData.mileage = newData.mileage;
      selectDateData.businessDistance = newData.businessDistance;
      selectDateData.toll = newData.toll;
      selectDateData.operatingAmount = newData.operatingAmount;
      selectDateData.lpgChargeAmount = newData.lpgChargeAmount;
      selectDateData.fuelEfficiency = newData.fuelEfficiency;
      selectDateData.lpgUsage = newData.lpgUsage;
    });
    console.log('데이터가 수정되었습니다.');
  }
};

// DELETE

아직 삭제하기 기능을 넣어주지 않았습니다.

 

readSelectDateRecord 적용


screens/Record.tsx

// react, react-native
import React, {useCallback, useEffect, useReducer, useState} from 'react';
import {NativeStackScreenProps} from '@react-navigation/native-stack';

// library

// realm

// component
import SubHeader from '../components/record/SubHeader';
import DrivingInfoRecord from '../components/record/DrivingInfoRecord';
import DrivingInfo from '../components/record/DrivingInfo';
import ButtonWrap from '../components/record/ButtonWrap';

// style
import {Record as Style} from '../styles/record.styles';
import * as RecordReducer from '../reducers/recordReducer';
import {readSelectDateRecord} from '../realm/recordRealmFunctions';

type RootStackParamList = {
  Profile: {postDate: string};
};

type profileProps = NativeStackScreenProps<RootStackParamList, 'Profile'>;

// 추가하기(+버튼 클릭시), 수정하기(달력에서 날짜 클릭, 수정 클릭)
const Record = ({route}: profileProps) => {
  const {postDate} = route.params;

  const [selectDate, setSelectDate] = useState(postDate); // 선택한 날짜
  const [record, setRecord] = useState(''); // CREATE or UPDATE
  const [state, dispatch] = useReducer(
    RecordReducer.reducer,
    RecordReducer.initialRecord,
  );

  // selectDate가 realm에 있는지 체크
  const readDB = useCallback(() => {
    const selectDateData = readSelectDateRecord(selectDate);

    if (selectDateData) {
      setRecord('UPDATE'); // 데이터 수정
      dispatch({type: 'initialize', payload: selectDateData});
    } else {
      setRecord('CREATE'); // 데이터 생성
      const initialData = {...RecordReducer.initialRecord, date: selectDate};
      dispatch({type: 'initialize', payload: initialData});
    }
  }, [selectDate]);

  useEffect(() => {
    readDB();
  }, [readDB, selectDate]);

  return (
    <Style.container>
      {/* 헤더 */}
      <SubHeader selectDate={selectDate} setSelectDate={setSelectDate} />

      <Style.scrollView>
        {/* 기본 운행 정보 기록하기 */}
        <DrivingInfoRecord state={state} dispatch={dispatch} />

        {/* 운행정보 */}
        <DrivingInfo state={state} />
      </Style.scrollView>

      {/* 취소, 저장 */}
      <ButtonWrap record={record} state={state} />
    </Style.container>
  );
};

export default Record;

 

CreateRecord, updateRecord 적용


components/record/ButtonWrap.tsx

// realm
import {createRecord, updateRecord} from '../../realm/recordRealmFunctions';

// component
import BasicsButton from '../common/BasicsButton';

// style
import {ButtonWrap as Style} from '../../styles/record.styles';
import {useNavigation} from '@react-navigation/native';
import {RecordType} from '../../types/types';

interface PropsType {
  record: string;
  state: RecordType;
}

const ButtonWrap = ({record, state}: PropsType) => {
  const navigation = useNavigation();

  const onGoBackPress = () => {
    navigation.goBack();
  };

  const onSavePress = () => {
    if (record === 'CREATE') {
      createRecord(state);
    } else {
      updateRecord(state);
    }

    navigation.goBack();
  };

  return (
    <Style.container>
      <BasicsButton text="취소" option="cancel" onButtonPress={onGoBackPress} />
      <BasicsButton text="저장" onButtonPress={onSavePress} />
    </Style.container>
  );
};

export default ButtonWrap;

 

readAllRecord 적용


components/common/CalendarView.tsx

// react, react-native
import React, {Dispatch, SetStateAction, useEffect, useState} from 'react';
import {View} from 'react-native';
import {Calendar, LocaleConfig} from 'react-native-calendars';
import {SvgXml} from 'react-native-svg';

// library
import dayjs from 'dayjs';

// assets, realm
import {svg} from '../../assets/svg';

// component

// style
import Theme from '../../styles/Theme';
import {readAllRecord} from '../../realm/recordRealmFunctions';

LocaleConfig.locales['ko'] = {
  monthNames: [
    '01월',
    '02월',
    '03월',
    '04월',
    '05월',
    '06월',
    '07월',
    '08월',
    '09월',
    '10월',
    '11월',
    '12월',
  ],
  monthNamesShort: [
    '1월',
    '2월',
    '3월',
    '4월',
    '5월',
    '6월',
    '7월',
    '8월',
    '9월',
    '10월',
    '11월',
    '12월',
  ],
  dayNames: [
    '일요일',
    '월요일',
    '화요일',
    '수요일',
    '목요일',
    '금요일',
    '토요일',
  ],
  dayNamesShort: ['일', '월', '화', '수', '목', '금', '토'],
  today: '오늘',
};
LocaleConfig.defaultLocale = 'ko';

interface PropsType {
  checkDate: string;
  setCheckDate: Dispatch<SetStateAction<string>>;
}

const CalendarView = ({checkDate, setCheckDate}: PropsType) => {
  // 현재 날짜: 년-월-일
  const currentDate = dayjs().format('YYYY-MM-DD');

  // realm에서 기록한 날짜 담기
  const [markedDate, setMarkedDate] = useState<
    Record<string, {marked: boolean}>
  >({});

  const readMarkedAllDB = () => {
    const data = readAllRecord();
    const newMarkedDate: Record<string, {marked: true}> = {};

    if (data) {
      data.forEach(record => {
        if (record.date) {
          newMarkedDate[record.date] = {marked: true};
        }
      });
      setMarkedDate({...newMarkedDate});
    } else {
      console.log('데이터가 없습니다.');
    }
  };

  useEffect(() => {
    readMarkedAllDB();
  }, []);

  const markedSelectedDates = {
    ...markedDate,
    [checkDate]: {
      selected: true,
      marked: markedDate[checkDate]?.marked,
      dotColor: Theme.colors.mainDeep,
      customStyles: {
        container: {
          backgroundColor: `${Theme.colors.mainLight}`,
          borderRadius: 10,
        },
        text: {
          color: `${Theme.colors.black}`,
        },
      },
    },
  };

  const customTheme = {
    dotColor: '#FF7B00',
    // year, month
    textSectionTitleColor: `${Theme.colors.black}`,
    textSectionTitleDisabledColor: `${Theme.colors.black}`,
    // day of week, day
    textDayHeaderFontSize: 14,
    textDayFontSize: 14,
    textDisabledColor: `${Theme.colors.grey}`,
    // today
    todayTextColor: `${Theme.colors.mainDeep}`,
  };

  // {"dateString": "2024-03-18", "day": 18, "month": 3, "timestamp": 1710720000000, "year": 2024}
  const onDayPress = (day: {dateString: SetStateAction<string>}) => {
    setCheckDate(day.dateString);
  };

  return (
    <View>
      <Calendar
        markingType={'custom'}
        markedDates={markedSelectedDates}
        onDayPress={onDayPress}
        maxDate={currentDate}
        theme={customTheme}
        monthFormat={'yyyy년 M월'}
        renderArrow={direction =>
          direction === 'left' ? (
            <SvgXml xml={svg.prev} />
          ) : (
            <SvgXml xml={svg.next} />
          )
        }
      />
    </View>
  );
};

export default CalendarView;
728x90
반응형