본문 바로가기
JavaScript/React Native

[React Native] Redux

by @김상현 2022. 1. 17.
반응형

개발환경...

더보기

System:
    OS: macOS 11.1
    CPU: (16) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 2.10 GB / 32.00 GB
    Shell: 5.8 - /bin/zsh
  Binaries:
    Node: 17.3.1 - /usr/local/bin/node
    Yarn: Not Found
    npm: 8.3.1 - /usr/local/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  Managers:
    CocoaPods: 1.11.2 - /usr/local/bin/pod
  SDKs:
    iOS SDK:
      Platforms: iOS 14.5, DriverKit 20.4, macOS 11.3, tvOS 14.5, watchOS 7.4
    Android SDK: Not Found
  IDEs:
    Android Studio: 4.2 AI-202.7660.26.42.7351085
    Xcode: 12.5.1/12E507 - /usr/bin/xcodebuild
  Languages:
    Java: 11.0.9.1 - /usr/bin/javac
  npmPackages:
    @react-native-community/cli: Not Found
    react: 17.0.2 => 17.0.2 
    react-native: 0.66.4 => 0.66.4 
    react-native-macos: Not Found
  npmGlobalPackages:
    *react-native*: Not Found

출처 :

https://redux.js.org/introduction/getting-started

 

Getting Started with Redux | Redux

Introduction > Getting Started: Resources to get started learning and using Redux

redux.js.org

1. Redux 설치하기
1
npm install redux
cs
2. redux 폴더 생성

필자는 기본적으로 루트디렉토리에 src 폴더를 만들고 사용하는 모든 파일을 넣는다.

redux 폴더 생성

3. reducer 작성

user.tsx

1
2
3
4
5
6
7
8
9
10
11
12
13
/*user.tsx*/
const initialState = null
 
export const userReducer = (
    state: WFSUser | null = initialState,
    action: { typeany, payload?: any })
    : WFSUser | null => {
    switch (action.type) {
        default:
            break;
    }
    return state
}
cs

유저의 기본적인 값들을 담을 userReducer를 만들어 줍니다.

리듀서는 두개의 값이 필수적입니다.  state 와 action 입니다.

  • state는 해당 리듀서가 반환하는 값의 타입을 지정합니다.
  • action은 리듀서에서 어떤 작업을 할지 정해주는 역할을 합니다.

userReducer는 유저가 로그인 하면 WFSUser 클래스를, 그렇지 않으면 null를 반환합니다.

/**22.01.18

Error: The slice reducer for key "user" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined. If you don't want to set a value for this reducer, you can use null instead of undefined.

undefined를 사용하면 안된답니다. 대신 null을 사용하라 합니다. 본문 내용은 수정하였습니다.

*/

*** state의 타입과 reducer의 return 타입은 동일해야합니다.***

 

reducer에 들어가는 뼈대를 만들었으니 이제 action 을 작성해봅시다.

4. action 작성

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
/*user.tsx*/
const initialState = null
 
export const updateUserInfo = (newUserState: WFSUser) => {
    return {
        type"UPDATE_USER_INFO",
        payload: newUserState
    }
}
export const initializeUserInfo = () => {
    return {
        type : "INITIALIZE_USER_INFO",
        payload : null
    }
}
 
export const userReducer = (
    state: WFSUser | null = initialState,
    action: { typeany, payload?: any })
    : WFSUser | null => {
    switch (action.type) {
        case "UPDATE_USER_INFO":
            return action.payload
        case "INITIALIZE_USER_INFO":
            return action.payload
        default:
            break;
    }
    return state
}
cs

위와 똑같은듯 비슷하죠? 같은 파일내에 작성했기 때문입니다.

새로 생긴 updateUserInfoinitializeUserInfo가 바로 action 입니다.

action 함수를 호출하면 userReducer에서 action.type을 통해 state(user)를 수정합니다.

 

5. type 작성

reducer에서는 어떤 작업을 수행할 지를 actiontype을 통해서 구분합니다.

위 "action작성"의 코드를 참고하여

우선 action에서 상태를 변경할 때 사용되는 payload와 함께 typereducer에게 보냅니다.

그러면 reducer에서는 switch를 통해 type을 확인하고 payload를 사용하여 상태를 수정하여 저장합니다.

 

이 때, 같은 문자열이 두 번 쓰입니다. 때문에 일반적으로 이를 따로 분리합니다. 아래와 같이 말이죠

user.type.tsx

이는 리듀서와 액션이 담긴 user.tsx와 같은 redux/reducer/user 폴더 안에 위치합니다.

 

자 그러면 완성된 user.tsx와 user.type.tsx를 살펴볼까요

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
32
33
34
35
36
37
//user.tsx
import { WFSUser } from "../../../classes/User";
import { INITIALIZE_USER_INFO, UPDATE_USER_INFO } from "./user.type";
 
const initialState = null
 
export const updateUserInfo = (newUserState: WFSUser) => {
    return {
        type: UPDATE_USER_INFO,
        payload: newUserState
    }
}
export const initializeUserInfo = () => {
    return {
        type : INITIALIZE_USER_INFO,
        payload : null
    }
}
 
export const userReducer = (
    state: WFSUser | null = initialState,
    action: { typeany, payload?: any })
    : WFSUser | null => {
    switch (action.type) {
        case UPDATE_USER_INFO:
            return action.payload
        case INITIALIZE_USER_INFO:
            return action.payload
        default:
            break;
    }
    return state
}
 
//user.type.tsx
export const UPDATE_USER_INFO = "UPDATE_USER_INFO"
export const INITIALIZE_USER_INFO = "INITIALIZE_USER_INFO"
cs
6. store 작성

store.tsx

src/redux 위치에 store.tsx 파일을 생성합니다.

1
2
3
4
5
6
7
8
9
10
11
import { combineReducers, createStore, Reducer, Store } from "redux";
import { userReducer } from "./reducer/user/user";
 
const rootReducer : Reducer = combineReducers({
    user : userReducer,
    //someState : someStateReducer
})
 
const store : Store = createStore(rootReducer);
 
export default store;
cs

그리고 위와 같이 작성합니다. 쉽죠? 

다른 reducer를 추가하려면 앞서 했던 reducer,action,type의 과정을 한 뒤에

주석처리한 someState : somStateReducer 와 같이 작성하시면 됩니다.

7. 사용법

이제 세팅은 모두 끝났습니다. 사용만 하면되죠.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Provider, useDispatch, useSelector } from 'react-redux'
import store from './src/redux/store';
import { updateUserInfo } from './src/redux/reducer/user/user';
const App = () => {
 
  const reduxState = useSelector((state: { user: WFSUser | null }) => state);
  const reduxDispatch = useDispatch();
 
  const updateuUserRedux = () => {
    reduxDispatch(updateUserInfo(new WFSUser("홍길동""email@email.com""email"false"uid")))
  }
  return (
    <Provider store={store}>
      <View>
        {/* <ThemeButton text="THEME_BUTTON" />
        <ScrollView
          contentInsetAdjustmentBehavior="automatic">
        </ScrollView> */}
      </View>
    </Provider>
  );
};
cs

<Provider stort={store}></Provider> 태그로 root tag 를 감싸주세요.

그럼 이제 <Provider>의 Child에서는 모두 store 가 가진 상태들을 사용할 수 있습니다.

 

우선 호출 방법은 다음과 같습니다.

useSelector()store의 상태가 변화 될때 마다 모든 state를 반환합니다.

이를 사용하시면 됩니다.

 

두번째로 상태 변경방법입니다.

useDispatch()reduxDispatch(변수명 자유롭게)로 선언해줍니다.

첫번째 매개변수로 앞서 정의한 action을 호출하여 상태를 변경할 수 있습니다.

 

8. 작동원리

Provider 태그를 사용하여 컴포넌트들을 감쌉니다.

useDispatch를 정의하고 첫번째 매개변수로 action을 호출합니다.

호출된 actiontypepayload를 반환합니다.(action : {type:any,payload?:any})

이를 useDispatch가 모든 reducer에게 넘겨줍니다.

reducer안에 switch에서 type을 검출하여 동일한 case를 실행시킵니다.

state가 변경됩니다.

 

부족함이 많은 블로그 찾아주셔서 감사드립니다.

추가적으로 잘못된 부분이나 궁금한 내용은 댓글을 남겨주세요.

반응형

댓글