일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- 스타트업
- 자바
- Redux
- 비전공
- react
- 비전공자
- 클론코딩
- react native
- 개발
- 인스타그램
- 스프링
- Java
- 개발자
- Spring
- 스프링 부트
- 백엔드
- 프론트 엔드
- 국비지원
- 리엑트
- 풀스택
- ffmpeg
- react-native
- 상태관리
- 리엑트 네이티브
- expo
- 코딩
- 풀스택 개발자
- spring boot
- 프론트엔드
- 국비 지원
- Today
- Total
오티스의개발일기
[REDUX] Redux Toolkit 사용해보기 + 로그인 버튼 Client 단부터 reducer 까지 -git첨부- 본문
[REDUX] Redux Toolkit 사용해보기 + 로그인 버튼 Client 단부터 reducer 까지 -git첨부-
안되면 될때까지.. 2022. 12. 21. 14:30
< 이전글
2022.12.21 - [개발/react-native] - [REACT NATIVE] Redux-Saga 프로젝트 시작하기
저번신간에 redux-saga에 대해서 작업해보았다
redux-saga를 공부하기전 redux-toolkit에 대해서도 미리 사전조사를 해보았다.
결과 적으로 두개다 쓸필요가 없다는 결론이 내려졌다.
toolkit에 있는 thunk 미들웨어로 비동기 처리를 진행하면되고 또한 이번 toolkit 에있는 미들웨어안에
pending,fulfilled,rejected 와 같은 상태를 관리해줄수 있기때문에
굳이 다같이 쓸필요는 없다고 느껴졌다.
그래도 redux-sage 의 공부는 필수적이라 생각했다.
redux middleware redux-saga 지금까지 공부해왔던게 빌드업이 하나하나 이루어진 느낌이다.
기본적으로 본인이 올린 글들은 순차적으로 올린글들이니 순차적으로 내글을 읽고 도움이됬으면 한다.
본론으로 돌아가 toolkit을 사용을 해보겠다.
일단 npm으로 toolkit을 다운로드 해준다
npm install @reduxjs/toolkit
or
yarn add @reduxjs/toolkit
store.js 이다.
그전에는
import { createStore, applyMiddleware } from "redux";
createStore을 사용해 store을 생성했지면 현재는 configureStore을 사용한다.
참고로 본인이 사용하고있는 redux가 최신꺼라면 createStore 이렇게 된모습을 볼수 있을것이다.
이제 더이상 redux에서 관리하지 않는다는 뜻이다.
그런이유도 있기에 더더웃 redux toolkit을 사용해야하는 이유가 아닐까 싶다.
#1. store.js 만들기
store.js
import {configureStore} from '@reduxjs/toolkit'
import rootReducer from "./src/reducers/rootReducer"; // 리듀서 모음집이라 생각하면된다
// 리듀서를 하나하나 만들어서 이곳에 생성해도 되지만 가독성을 위해 하나의 리듀서안에 여러가지를 넣고 사용한다.
const customMiddleware = (store) => (next) => (action) => {
console.log('로깅', action);
next(action)
console.log('로그끝');
}
// 위에서 만든 reducer를 스토어 만들때 넣어줍니다
let store = configureStore({
reducer: rootReducer,
devTools: process.env.NODE_ENV !== 'production', // 프로덕션 모드일때는 devTools 차단
//middleware: [customMiddleware], // 기본적으로 thunk 같은 미들웨어가 자동으로 포함되어 있다
// 추가적으로 원하는 커스텀 미들웨어를 배열형식으로 추가시키면된다.
});
export default store;
상단에 예전에 만들어놓은 customMiddleware가 보일것이다.
configureStore에 많은 옵션들을 넣을수 있고
기본적으로는 thunk가 내장되어있다.
예전처럼 applyMiddleware를 호출시킬 필요가없다
그리고 또한 커스텀미들웨어를 배열형식으로 추가시킬수있다.
주의할점
configureStore안에 reducer부분이다.
꼭! 그전 처럼
let store = createStore(
rootReducer,
composeWithDevTools(applyMiddleware(thunk)) // 미들웨어
);
이런식으로 넣으면 절대 안된다
꼭
reducer : rootReducer <<<<<< 이런식으로 넣어야 동작한다 그렇지않으면
이러한 에러를 보게될것이다.
Uncaught Error: "reducer" is a required argument, and must be a function or an object of functions that can be passed to combineReducers
이제 rootReducer를 만들어보자
#2. rootReducer.js 만들기
// /src/reducers/rootReducer.js
// 여러 reducer를 사용하는 경우 reducer를 하나로 묶어주는 메소드
// store에 저장되는 리듀서는 오직 1개이지만 그 1개에 여러개의 리듀서가 들어갈수있음
import { combineReducers } from "redux";
import userSlice from "./userReducer"; // 만든 리듀서'
// 이름도 알기쉽게 바꿔준다. userReducer => userSlice
const rootReducer = combineReducers({
userSlice : userSlice.reducer,
// redux toolkit
// userReducer : userReducer => userSlice : userSlice.reducer(),
});
export default rootReducer;
우리는 이제 reducer대신 slice라는것을 사용할것이다.
일단 이름을 slice로 바꿔준다.
이름을 slice로 바꾸는건 필수는 아니지만
본인은 가독성을 위해 다 바꾸는편이다.
여기서 특이한점은 userSclice.reducer 라고 적는다는 점이다.
이부분은 후에가서 설명하겠지만
간단하게 설명하면 userSlice안에 지정된 reducers 함수들을 쓴다는 의미이다.
이제 userReducer를 만들어보겠다.
#3. userReducer.js 만들기
// /src/reducers/userReducer.js
import { createSlice } from '@reduxjs/toolkit' // toolkit 추가된 임포트
import { logInRequest } from '../actions/userAction'
const initialState = {
loading: false,
user: null,
id: '',
password: '',
error: '',
}
const userSlice = createSlice({
name: 'userSlice',
initialState: initialState,
reducers: { // 동기적인 액션을 넣는다. 내부적인 액션
logOut (state, action) {
state.user = null
state.loading = false
},
id (state, action) {
state.id = action.payload
},
password (state, action) {
state.password = action.payload
},
},
extraReducers: { // 비동적인 엑션을 넣는다 외부적인 액션 (예를들어 userSlice에서 post의 액션을 써야할때 이곳에 적는데 그때는 동기가아니고 비동기여도 넣는다.)
[logInRequest.pending](state, action) {
state.loading = true;
},
[logInRequest.fulfilled](state, action) {
state.user = action.payload;
state.loading = false;
},
[logInRequest.rejected](state, action) {
console.log('rejected 됨')
console.log(action)
state.user = null;
state.loading = false;
},
}
});
// immer 기본 형태
// nextState = produce(prevState, (draft) => {})
// const userReducer = (state = initialState, action) => {
// return produce(state, (draft) => {
// const {type, payload} = action;
// switch (type) {
// case USER_ACTION_TYPE.USER_LOADING:
// draft.loading = true
// case USER_ACTION_TYPE.USER_LOG_IN_REQUEST:
// draft.loading = true
// case USER_ACTION_TYPE.USER_LOG_IN_SUCCESS:
// draft.user = payload
// draft.loading = true
// case USER_ACTION_TYPE.USER_LOG_IN_FAILURE:
// draft.loading = false
// case USER_ACTION_TYPE.USER_LOG_OUT_REQUEST:
// draft.loading = true
// case USER_ACTION_TYPE.USER_LOG_OUT_SUCCESS:
// draft.user = null
// draft.loading = false
// case USER_ACTION_TYPE.USER_LOG_OUT_FAILURE:
// draft.loading = false
// default:
// return state
// }
// })
// }
export default userSlice;
아래의 userReducer은 redux-toolkit 을 사용하기전에 썼던 reducer이다 서로 비교하며 확인하길 바란다.
이제는 type을 맞추는 대신 함수를 만들어서 사용하는것을 볼수있다.
이제 더이상 type은 맞출 필요가없다. type은 후에나올 action에서 prefix의 이름을 지정해주면
그후 redux-toolkit 알아서 랜덤하게 이름을 만들어준다.
너무나 간편한 툴인게 확 느껴지는 부분이다.
또한 추가적으로 immr이 기본적으로 탑재되어있어
더이상 불변성을 지킬 필요가없다 (...state 쓸필요가 없음.)
나머지 추가설명은 주석에 남겨놓았으니 확인바란다.
#3. userAction.js 만들기
import {createAsyncThunk} from '@reduxjs/toolkit'
const loginApi = (params) => {
console.log(params.id) // 아이디
console.log(params.password) // 비밀번호
//params = 받은 파라미터
// axios 를 따로 구현안하고 가짜로 넘김
return {userId: 1, nickName: '홍길동'} // api 결과
}
const logInRequest = createAsyncThunk('user', async (data, {dispatch, getState, rejectWithValue, fulfillWithValue}) => {
// try catch 는 하지말아야 에러를 캐치할수 있다.
// 상단 파라미터중 data는 요청시 들어온 파라미터이다. 저 파라미터를 가지고 서버에 데이터 요청하면된다.
console.log('data = ', data) // 파라미터
const state = getState(); // 상태가져오기
console.log('state = ', state)
let params = {}
params['id'] = state.userSlice.id
params['password'] = state.userSlice.password
let result = loginApi(params);
if (result.nickName === '홍길동') {
throw rejectWithValue('아이디가 다릅니다.');
} else {
return result;
}
})
export {logInRequest}
createAsyncThunk 안에 매게변수를 보아라
data는 함수를 호출하면서 클라이언트단에서 넣은 매게변수이고
그두번째는 ThunkAPI 이다.
dispatch, getState, rejectWithValue, fulfillWithValue
이렇게 4개가 있고
const logInRequest = createAsyncThunk('user', async (data, ThunkApi)
이런식으로 작성하여
ThunkApi.getState()
이렇게 꺼내 쓸수도있다.
우리는 저기있는 thunk에서 제공한 비동기 api로
성공 실패를 구별할수있고 컨트롤 할수있다.
기본적으로 성공과 실패 예시를 만들어놓았다.
이제 클라이언트 단을 확인해보자 방금 만든 userAction.js가 좀더 쉽게 이해될것이다.
import {View, Button, Text, TextInput} from 'react-native';
import { useDispatch, useSelector } from 'react-redux'; // userDispatch = 데이터 변경시 사용 // useSelector = 데이터 가져올때 사용
import {logInRequest, logOutRequest} from "../actions/userAction";
import userSlice from "../reducers/userReducer";
const LoginScreen = () => {
const dispatch = useDispatch();
const user = useSelector(state => state.userSlice);
// state.userReducer
// state 는 전체 이니셜스테이트 데이터
// state.userReducer = ../reducers/rootReducer 안에 userReducer << 이친구를 가르키고있다. : userReducer,
const loginApi = () => {
if (user.id.length === 0) {
alert('아이디를 입력해주세요')
return false
}
if (user.password.length === 0) {
alert('비밀번호를 입력해주세요')
return false
}
dispatch(logInRequest());
}
const logOutApi = () => {
dispatch(userSlice.actions.logOut());
}
return (
<View>
{!user.user ?
<Button title={"로그인"} onPress={loginApi}></Button>
: <Button title={"로그 아웃"} onPress={logOutApi}></Button>
}
<View>
{
user.loading ? <Text>로그인인중</Text> : user.user ? <Text>{user.user.nickName}</Text> : <Text>로그인해주세요</Text>
}
</View>
<View>
<Text>{user.id}</Text>
<Text>{user.password}</Text>
</View>
<View>
<TextInput placeholder={"아이디"} onChangeText={(id) => dispatch(userSlice.actions.id(id))}></TextInput>
<TextInput placeholder={"비밀번호"} onChangeText={(password) => dispatch(userSlice.actions.password(password))}></TextInput>
</View>
</View>
);
}
export default LoginScreen;
기본적으로
만약 user.loading = true 라면 로그인중 혹은 로그아웃중
만약 user.user가 존재하면 닉네임을 반환
로그인버튼을 클릭시 id와 password 의 길이가 0 이면 경고를 내뿝는다.
그게아니라면 userAction.js 에서 만든 loginRequest를 dispatch안에 넣어 실행한다.
실행이되고 그결과는 userReducer로 넘어가 결과를 업데이트한다.
이렇게 redux-toolkit이 끝이났다.
이제 어느정도 데이터 관련 공부는 끝이난거같다
마지막으로 axios 에대해 잠깐 설명하고 나머지는
유튜브에서 어플리케이션 UI 클론 영상을보며 좀 따라하다 어느정도 공부한후
백단과 같이 만들며 포스팅 해보도록하겠다.
깃은 아래에 첨부해놨으니 확인하길 바란다.
https://github.com/1domybest/react-native-redux-toolkit.git
'개발 > react-native' 카테고리의 다른 글
[REACT-NATIVE] Redux Toolkit 과 Styled Components를 사용하여 자동 다크모드 라이트모드 구현하기 (2) | 2022.12.23 |
---|---|
[REACT NATIVE] 리엑트 네이티브 인스타그램 클론 코딩 (1) 계획 및 프로젝트 네비게이션 생성 및 홈 화면 구현 -git 참조- (0) | 2022.12.22 |
[REACT NATIVE] Redux-Saga 프로젝트 시작하기 -git첨부- (0) | 2022.12.21 |
[REACT NATIVE] IMMER 사용하기 + REDUX 추가설명 -git첨부- (0) | 2022.12.20 |
[REACT NATIVE] REDUX 미들웨어 그리고 클라이언트단부터의 로직의 흐름 (0) | 2022.12.20 |