Browse Source

[Redux] /basis/drone toolkit 적용

master
junh_eee(이준희) 7 months ago
parent
commit
096547e623
  1. 39
      src/_redux/features/basis/drone/droneSlice.ts
  2. 6
      src/_redux/features/basis/drone/droneState.ts
  3. 295
      src/_redux/features/basis/drone/droneThunk.ts
  4. 2
      src/_redux/features/comn/message/messageSlice.ts
  5. 8
      src/_redux/rootReducer.ts
  6. 5
      src/components/message/MessageErrorModal.js
  7. 14
      src/components/message/MessageInfoModal.js
  8. 44
      src/containers/basis/dron/BasisDronContainer.js
  9. 48
      src/containers/basis/dron/BasisDronDetailContainer.js
  10. 38
      src/containers/basis/dron/BasisIdntfContainer.js
  11. 16
      src/redux/reducers/rootReducer.ts

39
src/_redux/features/basis/drone/droneSlice.ts

@ -1,13 +1,26 @@
import { createSlice } from '@reduxjs/toolkit';
import { initDron } from './droneState';
import { getDroneList } from './droneThunk';
import {
createIdntf,
deleteIdntf,
getDroneDetail,
getDroneList,
getIdntfList
} from './droneThunk';
const droneSlice = createSlice({
name: 'droneSlice',
initialState: initDron,
reducers: {
testClient: (state, action) => {
state.testClient = action.payload;
clientResetIdntf: state => {
state.droneDetail = undefined;
state.idntfList = undefined;
state.isRefreshIdntf = false;
state.idntfCount = 0;
},
clientSelectGroup: (state, action) => {
const selectData = action.payload;
state.selectGroup = selectData;
}
},
extraReducers: builder => {
@ -16,9 +29,25 @@ const droneSlice = createSlice({
state.droneList = data.items;
state.droneTotal = data.total;
});
builder.addCase(getDroneDetail.fulfilled, (state, action) => {
const data = action.payload;
state.droneDetail = data;
});
builder.addCase(getIdntfList.fulfilled, (state, action) => {
const { data, count } = action.payload;
state.idntfList = data;
state.idntfCount = count;
state.isRefreshIdntf = false;
});
builder.addCase(createIdntf.fulfilled, (state, action) => {
state.isRefreshIdntf = true;
});
builder.addCase(deleteIdntf.fulfilled, (state, action) => {
state.isRefreshIdntf = true;
});
}
});
export const { testClient } = droneSlice.actions;
export const { clientResetIdntf, clientSelectGroup } = droneSlice.actions;
export const droneReducer2 = droneSlice.reducer;
export const droneReducer = droneSlice.reducer;

6
src/_redux/features/basis/drone/droneState.ts

@ -8,9 +8,7 @@ export const initDron: IDroneState = {
selectGroup: undefined,
isRefreshIdntf: false,
page: 1,
testClient: ''
page: 1
};
export interface IDroneState {
@ -24,8 +22,6 @@ export interface IDroneState {
selectGroup: ISelectGroup | undefined;
isRefreshIdntf: boolean | false;
page: number | 1;
testClient: string | '';
}
export interface ISelectGroup {

295
src/_redux/features/basis/drone/droneThunk.ts

@ -2,13 +2,20 @@ import axios from '../../../../modules/utils/customAxiosUtil';
import qs from 'qs';
import { createAsyncThunk } from '@reduxjs/toolkit';
import { isError } from '../../comn/message/messageSlice';
import { ERROR_MESSAGE } from '@src/configs/constants';
import { isError, isMessage } from '../../comn/message/messageSlice';
import {
ERROR_MESSAGE,
DUPLATE_MESSAGE,
SAVE_MESSAGE,
DELETE_MESSAGE
} from '@src/configs/constants';
import { ICreateDroneRq, ICreateIdntfRq, IUpdateDroneRq } from './droneState';
// 드론 목록 조회
export const getDroneList = createAsyncThunk(
'basis/getDroneList',
async (rq: string, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const queryString = qs.stringify(rq, {
addQueryPrefix: true,
@ -19,7 +26,7 @@ export const getDroneList = createAsyncThunk(
const { data, errorCode } = res;
if (errorCode) {
return errorCode;
throw Error;
}
return data;
@ -32,12 +39,288 @@ export const getDroneList = createAsyncThunk(
isRefresh: false
})
);
return rejectWithValue(error);
}
}
);
// 드론 상세 조회
// export const getDroneDetail = createAsyncThunk(
// 'basis/getDroneDetail',
export const getDroneDetail = createAsyncThunk(
'basis/getDroneDetail',
async (id: number, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const res: any = await axios.get(`api/bas/dron/detail/${id}`);
return res.data;
} catch (error) {
return rejectWithValue(error);
}
}
);
// 드론 생성
export const createDrone = createAsyncThunk(
'basis/createDrone',
async (rq: ICreateDroneRq, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const { data } = await axios.post('api/bas/dron/create', rq);
if (data.result) {
thunkAPI.dispatch(
isMessage({
messageCode: SAVE_MESSAGE.code,
message: SAVE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
if (data.errorCode === 'DT002') {
thunkAPI.dispatch(
isError({
errorCode: DUPLATE_MESSAGE.code,
errorMessage: '제작번호 ' + DUPLATE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
} else {
throw Error;
}
}
} catch (error) {
thunkAPI.dispatch(
isError({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
rejectWithValue(error);
}
}
);
// 드론 수정
export const updateDrone = createAsyncThunk(
'basis/updateDrone',
async (rq: IUpdateDroneRq, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const { data } = await axios.put('api/bas/dron/update', rq);
if (data.result) {
thunkAPI.dispatch(
isMessage({
messageCode: SAVE_MESSAGE.code,
message: SAVE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
if (data.errorCode === 'DT002') {
thunkAPI.dispatch(
isError({
errorCode: DUPLATE_MESSAGE.code,
errorMessage: '제작번호 ' + DUPLATE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
} else {
throw Error;
}
}
} catch (error) {
thunkAPI.dispatch(
isError({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
rejectWithValue(error);
}
}
);
// 드론 삭제
export const deleteDrone = createAsyncThunk(
'basis/deleteDrone',
async (id: number, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const { data } = await axios.delete(`api/bas/dron/delete/${id}`);
if (data.result) {
thunkAPI.dispatch(
isMessage({
messageCode: DELETE_MESSAGE.code,
message: DELETE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
} else {
throw Error;
}
} catch (error) {
thunkAPI.dispatch(
isError({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
rejectWithValue(error);
}
}
);
// 식별장치 목록 조회
export const getIdntfList = createAsyncThunk(
'basis/getIdntfList',
async (id: number, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const res: any = await axios.get(`api/bas/dron/idntf/list/${id}`);
const { data, count, errorCode } = res;
if (errorCode) {
thunkAPI.dispatch(
isError({
errorCode: errorCode,
errorMessage: '처리중 오류가 발생하였습니다',
isHistoryBack: false,
isRefresh: false
})
);
throw Error;
}
const list = data
? [
{
...data,
isSave: true,
id: data?.idntfNum,
idntfNum: data.idntfNum.substring(2)
}
]
: [];
return { data: list, count: count };
} catch (error) {
return rejectWithValue(error);
}
}
);
// 식별장치 생성, 수정
export const createIdntf = createAsyncThunk(
'basis/createIdntf',
async (
rq: { mode: string; data: ICreateIdntfRq[]; arcrftSno: number },
thunkAPI
) => {
const { rejectWithValue } = thunkAPI;
try {
let res;
if (rq.mode === 'create') {
res = await axios.post('api/bas/dron/idntf/create', {
data: rq.data,
arcrftSno: rq.arcrftSno
});
} else {
res = await axios.put(`api/bas/dron/idntf/update/${rq.arcrftSno}`, {
idntfNum: rq.data[0].idntfNum,
ownerNm: rq.data[0].ownerNm,
hpno: rq.data[0].hpno
});
}
const { data } = res;
if (data.result) {
thunkAPI.dispatch(
isMessage({
messageCode: SAVE_MESSAGE.code,
message: SAVE_MESSAGE.message,
isHistoryBack: true,
isRefresh: false
})
);
return data;
} else {
if (data.errorCode === 'DT002') {
thunkAPI.dispatch(
isError({
errorCode: DUPLATE_MESSAGE.code,
errorMessage: '식별번호가 ' + DUPLATE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
} else {
throw Error;
}
}
} catch (error) {
thunkAPI.dispatch(
isError({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
return rejectWithValue(error);
}
}
);
// 식별장치 삭제
export const deleteIdntf = createAsyncThunk(
'basis/deleteIdntf',
async (id: string, thunkAPI) => {
const { rejectWithValue } = thunkAPI;
try {
const { data }: any = await axios.delete(
`api/bas/dron/idntf/delete/${id}`
);
// )
if (data.result) {
thunkAPI.dispatch(
isMessage({
messageCode: DELETE_MESSAGE.code,
message: DELETE_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
return data;
} else {
throw Error;
}
} catch (error) {
thunkAPI.dispatch(
isError({
errorCode: ERROR_MESSAGE.code,
errorMessage: ERROR_MESSAGE.message,
isHistoryBack: false,
isRefresh: false
})
);
return rejectWithValue(error);
}
}
);

2
src/_redux/features/comn/message/messageSlice.ts

@ -39,3 +39,5 @@ const msgSlice = createSlice({
});
export const { isMessage, isNoMessage, isError, isNoError } = msgSlice.actions;
export const messageReducer2 = msgSlice.reducer;

8
src/_redux/rootReducer.ts

@ -1,11 +1,13 @@
import { combineReducers } from '@reduxjs/toolkit';
import { droneReducer2 } from './features/basis/drone/droneSlice';
import { droneReducer } from './features/basis/drone/droneSlice';
import { laancReducer } from './features/laanc/laancSlice';
import { messageReducer2 } from './features/comn/message/messageSlice';
const rootReducer = (state: any, action: any) => {
const combineReducer = combineReducers({
drone: droneReducer2,
laanc: laancReducer
drone: droneReducer,
laanc: laancReducer,
message: messageReducer2
});
return combineReducer(state, action);

5
src/components/message/MessageErrorModal.js

@ -16,6 +16,11 @@ export const MessageErrorModal = props => {
state => state.messageState
);
// [Redux] 네이밍 작업 후 교체 필요
// const { isError, errorCode, errorMessage } = useSelector(
// state => state.messageState2
// );
// useEffect(() => {
// }, [isError]);

14
src/components/message/MessageInfoModal.js

@ -1,5 +1,9 @@
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import {
useDispatch as useDispatch2,
useSelector as useSelector2
} from '@src/redux/storeConfig/store';
import {
Button,
Modal,
@ -9,19 +13,25 @@ import {
} from '@component/ui';
import * as Actions from '../../modules/comn/message/actions/comnMessageAction';
import { useHistory } from 'react-router-dom';
import { isNoMessage } from '@src/_redux/features/comn/message/messageSlice';
export const MessageInfoModal = props => {
const dispatch = useDispatch();
const dispatch2 = useDispatch2();
const history = useHistory();
const { isMessage, MessageCode, message, isHistoryBack, isRefresh } =
useSelector(state => state.messageState);
// useEffect(() => {
// [Redux] 네이밍 작업 후 교체 필요
// const { isMessage, MessageCode, message, isHistoryBack, isRefresh } =
// useSelector(state => state.messageState2);
// }, [isError]);
const handlerClose = () => {
dispatch(Actions.ISNO_MESSAGE());
// [Redux] 네이밍 작업 후 교체 필요
// dispatch2(isNoMessage());
if (isHistoryBack) {
history.goBack();
}

44
src/containers/basis/dron/BasisDronContainer.js

@ -1,5 +1,9 @@
import { useEffect, useState } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import {
useDispatch as useDispatch2,
useSelector as useSelector2
} from '@src/redux/storeConfig/store';
import { useHistory, Link } from 'react-router-dom';
import { Button } from '@component/ui';
import * as DroneActions from '../../../modules/basis/drone/actions';
@ -8,16 +12,22 @@ import { GET_ARCTFT_TYPE_CD } from '../../../utility/CondeUtil';
import { GET_WGHT_TYPE_CD } from '../../../utility/CondeUtil';
import { BasisContainer } from '../BasisContainer';
import { BasisDataGrid } from '../../../components/basis/BasisDataGrid';
import { getDroneList } from '@src/_redux/features/basis/drone/droneThunk';
import {
clientResetIdntf,
clientSelectGroup
} from '@src/_redux/features/basis/drone/droneSlice';
export const BasisDronContainer = props => {
const dispatch = useDispatch();
const history = useHistory();
const originDispatch = useDispatch();
const dispatch = useDispatch2();
// 현재 활성화한 그룹 정보
const { selectGroup } = useSelector(state => state.droneState);
const history = useHistory();
// 기체 목록, 총 기체 수
const { droneList, droneTotal } = useSelector(state => state.droneState);
// 기체 목록, 총 기체 수, 현재 활성화한 그룹 정보
const { droneList, droneTotal, selectGroup } = useSelector2(
state => state.droneState
);
// 유저 정보
const { user } = useSelector(state => state.authState, shallowEqual);
@ -162,11 +172,11 @@ export const BasisDronContainer = props => {
cstmrSno: user?.cstmrSno
});
if (user.authId === 'SUPER' || user.authId === 'ADMIN') {
dispatch(
originDispatch(
GroupActions.getGroupList.request({ cstmrSno: user?.cstmrSno })
);
} else {
dispatch(
originDispatch(
GroupActions.getJoinGroupList.request({
cstmrSno: user?.cstmrSno
})
@ -179,15 +189,12 @@ export const BasisDronContainer = props => {
const handlerPageChange = page => {
const param = params;
param.page = page;
// dispatch(DroneActions.getDroneList.request({ searchParams: param }));
dispatch(DroneActions.getDroneList.request(param));
dispatch(getDroneList(param));
};
// 상세보기 선택 시
const handlerDetail = (groupId, groupNm, groupAuthCd, myGroupAuthCd) => {
dispatch(
DroneActions.clientSelectGroup({ groupId: groupId, groupNm: groupNm })
);
dispatch(clientSelectGroup({ groupId: groupId, groupNm: groupNm }));
localStorage.setItem('dronGroupId', groupId);
localStorage.setItem('dronGroupNm', groupNm);
setParams({
@ -195,7 +202,12 @@ export const BasisDronContainer = props => {
groupId: groupId,
groupNm: groupNm
});
dispatch(DroneActions.getDroneList.request({ groupId: groupId, page: 1 }));
dispatch(
getDroneList({
groupId: groupId,
page: 1
})
);
//기체등록버튼 활성/비활성 제어
let my = false;
@ -215,13 +227,13 @@ export const BasisDronContainer = props => {
// 기체 등록 화면으로 이동
const handlerGroupCreate = () => {
dispatch(DroneActions.clientResetIdntf()); // 초기화 진행
dispatch(clientResetIdntf()); // 초기화
history.push(`/basis/dron/create`);
};
// 상세보기 선택취소 시
const handlerCancel = () => {
dispatch(DroneActions.clientSelectGroup());
dispatch(clientSelectGroup());
setParams({
...params,

48
src/containers/basis/dron/BasisDronDetailContainer.js

@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
import { Col, Row } from '../../../components/ui/index';
import { Button } from '@component/ui';
import { useForm } from 'react-hook-form';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';
// yup
import * as yup from 'yup';
import { yupResolver } from '@hookform/resolvers/yup';
@ -14,32 +14,26 @@ import { droneAPI } from '../../../modules/basis/drone/apis';
import { IMG_PATH } from '../../../configs/constants';
import {
useDispatch as useDispatch2,
useDispatch,
useSelector as useSelector2
} from '../../../redux/storeConfig/store';
import { getDroneList } from '../../../_redux/features/basis/drone/droneThunk';
import { testClient } from '../../../_redux/features/basis/drone/droneSlice';
import { clientResetIdntf } from '@src/_redux/features/basis/drone/droneSlice';
import {
createDrone,
deleteDrone,
getDroneDetail,
updateDrone
} from '@src/_redux/features/basis/drone/droneThunk';
export const BasisDronDetailContainer = props => {
const dispatch2 = useDispatch2();
const testValue = useSelector2(state => state.droneState2);
const testHandler = () => {
dispatch2(getDroneList({ groupId: '2A60F8', page: 1 }));
dispatch2(testClient('test'));
};
useEffect(() => {
console.log(testValue, '---testVal');
}, [testValue]);
const dispatch = useDispatch();
const titleName = ' 기체 관리';
const dispatch = useDispatch();
// 가입한 그룹목록, 전체 그룹목록
const { joinList, groupList } = useSelector(state => state.groupState);
// 기체 상세정보, 선택한 기체정보
const { droneDetail, selectData } = useSelector(state => state.droneState);
const { droneDetail, selectData } = useSelector2(state => state.droneState);
// 유저 정보
const { user } = useSelector(state => state.authState);
@ -122,7 +116,7 @@ export const BasisDronDetailContainer = props => {
handlerSearch();
setPageType('update');
}
return () => dispatch(Actions.clientResetIdntf());
return () => dispatch(clientResetIdntf());
}, []);
// 기체 정보 존재 할 경우 데이터 셋팅
@ -227,7 +221,7 @@ export const BasisDronDetailContainer = props => {
// 기체 상세정보 요청
const handlerSearch = () => {
dispatch(Actions.getDroneDetail.request(props.id));
dispatch(getDroneDetail(props.id));
};
// 기체 생성
@ -238,7 +232,7 @@ export const BasisDronDetailContainer = props => {
createUserId: user?.userId,
updateUserId: user?.userId
};
dispatch(Actions.createDrone.request(saveData));
dispatch(createDrone(saveData));
};
// 기체 수정
@ -250,12 +244,12 @@ export const BasisDronDetailContainer = props => {
updateUserId: user?.userId
};
dispatch(Actions.updateDrone.request(saveData));
dispatch(updateDrone(saveData));
};
// 기체 삭제
const handlerDelete = async data => {
dispatch(Actions.deleteDrone.request(droneDetail.arcrftSno));
dispatch(deleteDrone(droneDetail.arcrftSno));
};
return (
@ -311,16 +305,6 @@ export const BasisDronDetailContainer = props => {
) : (
<></>
)}
<Button
ripple
className='ml-1'
color='primary'
size='sm'
onClick={testHandler}
>
테스트
</Button>
</div>
</Col>
</Row>

38
src/containers/basis/dron/BasisIdntfContainer.js

@ -1,9 +1,17 @@
import { useEffect, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useSelector } from 'react-redux';
import { Card, CardBody, Col, Row } from '@component/ui';
import { BasisIdntfForm } from '../../../components/basis/dron/BasisIdntform';
import * as Actions from '../../../modules/basis/drone/actions';
import ErrorModal from '../../../components/modal/ErrorModal';
import {
useDispatch,
useSelector as useSelector2
} from '@src/redux/storeConfig/store';
import {
createIdntf,
deleteIdntf,
getIdntfList
} from '@src/_redux/features/basis/drone/droneThunk';
export const BasisIdntfContainer = props => {
const dispatch = useDispatch();
@ -13,9 +21,10 @@ export const BasisIdntfContainer = props => {
const [idntDataList, setIdntfDataList] = useState([]);
// 식별장치 목록, 기체 상세정보
const { idntfList, droneDetail, isRefreshIdntf } = useSelector(
const { idntfList, droneDetail, isRefreshIdntf } = useSelector2(
state => state.droneState
);
// 유저 정보
const { user } = useSelector(state => state.authState);
@ -78,7 +87,8 @@ export const BasisIdntfContainer = props => {
// 식별장치 목록 요청
const handlerSearch = () => {
dispatch(Actions.getIdntfList.request(props.id));
// dispatch(Actions.getIdntfList.request(props.id));
dispatch(getIdntfList(props.id));
};
// 식별장치 추가(+ 유효성검사)
@ -164,15 +174,22 @@ export const BasisIdntfContainer = props => {
};
});
// originDispatch(
// Actions.createIdntf.request({
// mode,
// arcrftSno: droneDetail?.arcrftSno,
// data: createRq
// // data: saveArr.map(i => ({
// // ...i,
// // idntfNum: `PA${i.idntfNum}`
// // }))
// })
// );
dispatch(
Actions.createIdntf.request({
createIdntf({
mode,
arcrftSno: droneDetail?.arcrftSno,
data: createRq
// data: saveArr.map(i => ({
// ...i,
// idntfNum: `PA${i.idntfNum}`
// }))
})
);
} else {
@ -209,7 +226,8 @@ export const BasisIdntfContainer = props => {
if (!isSave) {
setIdntfDataList(idntDataList.filter(item => item.id !== id));
} else {
dispatch(Actions.deleteIdntf.request(id));
// dispatch(Actions.deleteIdntf.request(id));
dispatch(deleteIdntf(id));
}
};

16
src/redux/reducers/rootReducer.ts

@ -18,7 +18,7 @@ import {
analysisSimulatorSaga,
analysisSimulatorReducer
} from '../../modules/analysis/simulation';
import { droneSaga, droneReducer } from '../../modules/basis/drone';
// import { droneSaga, droneReducer } from '../../modules/basis/drone';
import { basGroupSaga, groupReducer } from '../../modules/basis/group';
import { messageReducer } from '../../modules/comn/message';
import {
@ -37,9 +37,10 @@ import { qnaSaga, qnaReducer } from '../../modules/cstmrService/inquiry';
import { mainDashSaga, mainDahReducer } from '../../modules/main/dash';
import { menuReducer } from '../../modules/menu';
import { statisticsSaga, statisticsReducer } from '../../modules/statistics';
import { droneReducer2 } from '../../_redux/features/basis/drone/droneSlice';
import { droneReducer } from '../../_redux/features/basis/drone/droneSlice';
import { laancReducer } from '../../_redux/features/laanc/laancSlice';
import { layoutReducer } from '../../_redux/features/layout/layoutSlice';
import { messageReducer2 } from '../../_redux/features/comn/message/messageSlice';
export function* saga() {
yield all([fork(mainDashSaga)]);
@ -48,7 +49,7 @@ export function* saga() {
yield all([fork(accountSaga)]);
yield all([fork(authSaga)]);
yield all([fork(basGroupSaga)]);
yield all([fork(droneSaga)]);
// yield all([fork(droneSaga)]);
yield all([fork(analysisSimulatorSaga)]);
yield all([fork(findSaga)]);
// yield all([fork(laancSaga)]);
@ -62,7 +63,7 @@ const rootReducer = combineReducers({
mainDashState: mainDahReducer,
messageState: messageReducer,
groupState: groupReducer,
droneState: droneReducer,
// droneState: droneReducer,
authState: authReducer,
accountState: accountReducer,
userPageState: userPageReducer,
@ -81,10 +82,11 @@ const rootReducer = combineReducers({
faqState: faqReducer,
qnaState: qnaReducer,
statisticsState: statisticsReducer,
// -----------------------------------------------
// ------------------------------------------------
droneState2: droneReducer2,
layoutState: layoutReducer
droneState: droneReducer,
layoutState: layoutReducer,
messageState2: messageReducer2
});
export default rootReducer;

Loading…
Cancel
Save