Develop/React & React Native

[노마드코더] 초보자를 위한 리덕스 101

안다희 2020. 3. 31. 04:17
728x90

*** 포스팅 목적이 아닌 기록/공부 목적으로 작성한 글이라, 건너뛴 부분이 많습니다!

 

# 필요한 코드만 요약

- package.json

"scripts": {
  "postinstall": "rndebugger-open"
}

 

- 설치

$ yarn add redux react-redux @reduxjs/toolkit redux-devtools-extension redux-thunk
$ yarn add react-native-debugger-open --save-dev
$ yarn postinstall

 

*** 최종코드

import {createStore, applyMiddleware} from 'redux';
import {createSlice} from '@reduxjs/toolkit';
import {composeWithDevTools} from 'redux-devtools-extension';
import thunk from 'redux-thunk';

const initialState = {
  isLoaded: false,
};

const slice = createSlice({
  name: 'reducer',
  initialState,
  reducers: {
    setIsLoadedReducer: (state, action) => {
      state.isLoaded = action.payload;
    },
  },
});

export const {setIsLoadedReducer} = slice.actions;

export const setIsLoadedAsync = (isLoaded: boolean) => {
  return async (dispatch, getState) => {
    try {
      console.log('왔으');
      dispatch(setIsLoadedReducer(isLoaded));
    } catch (error) {
      // notiE
    }
  };
};

const store = createStore(
  slice.reducer,
  composeWithDevTools(applyMiddleware(thunk)),
);

export default store;
import React from 'react';
import {connect} from 'react-redux';

import {setIsLoadedAsync} from '../redux/store';

const Text = styled.Text``;

const Test = props => {
  const {isLoaded, setIsLoaded} = props;
  const handleToggle = () => {
    setTimeout(() => setIsLoaded(!isLoaded), 1000);
    // setIsLoadedAsync(!isLoaded);
  };
  return (
    <Container>
      <Button onPress={handleToggle}>
        <Text>toggle</Text>
      </Button>
      <Text>{isLoaded ? 'loaded' : 'loading...'}</Text>
    </Container>
  );
};

const mapStateToProps = state => {
  return {
    isLoaded: state.isLoaded,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    setIsLoaded: (isLoaded: boolean) => dispatch(setIsLoadedAsync(isLoaded)),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Test);

 

 

원리 파헤치자

 

 

1) 기본 + 개발툴

import {createStore} from 'redux';
import {composeWithDevTools} from 'redux-devtools-extension';

export const SET_IS_LOADED = 'SET_IS_LOADED';

const initialState = {
  setIsLoaded: false,
};

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case SET_IS_LOADED:
      console.log('SET_IS_LOADED', action);
      return {...state, isLoaded: action.isLoaded};
    default:
      return state;
  }
};

const store = createStore(reducer, composeWithDevTools(applyMiddleware()));

export default store;

 

 

  const {isLoaded} = store.getState();

  const handleToggle = () => {
    store.dispatch({type: SET_IS_LOADED, isLoaded: true});
  };

직접 store. 해주기

 

2) map~ToProps, actionCreators 만들어주기

const setIsLoaded = (isLoaded: boolean) => ({
  type: SET_IS_LOADED,
  isLoaded,
});

export const actionCreators = {
  setIsLoaded,
};

 

 

const mapStateToProps = state => {
  return {
    isLoaded: state.isLoaded,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    setIsLoaded: (isLoaded: boolean) =>
      dispatch(actionCreators.setIsLoaded(isLoaded)),
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(Test);

그럼 props에서 얘네 쓸 수 있으~

 

3-1) toolkit: createAction

   2) 의 첫번째 setIsLoaded 대신

import {createAction} from '@reduxjs/toolkit';

const setIsLoaded = createAction('SET_IS_LOADED');

그리고 case에서 .type으로 바꾸고 .payload로 바꾸기

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case setIsLoaded.type: // this!!
      return {...state, isLoaded: action.payload}; // this!! payload
    default:
      return state;
  }
};

 

3-2) toolkit: createReducer

원래 reducer 대신

const reducer = createReducer(initialState, {
  [setIsLoaded]: (state, action) => {
    state.isLoaded = action.payload; // 이렇게 mutate를 할 수 있지!!!!!
  },
});

원래 못하던 mutate를 여기선 하지!!

 

3-3) toolkit: 개발툴. 설치는 1) 에서 했다~

 

3-4) toolkit: createSlice

- 3-2의 reducer를 이렇게!

const slice = createSlice({
  name: 'reducer',
  initialState,
  reducers: {
    setIsLoaded: (state, action) => {
      state.isLoaded = action.payload;
    },
  },
});

const store = createStore(
  slice.reducer,
  composeWithDevTools(applyMiddleware()),
);

export const {setIsLoaded} = slice.actions;

그리고 actionCreators 없어졌으니 쓸 때는

import {setIsLoaded} from '../redux/store';

const mapDispatchToProps = dispatch => {
  return {
    setIsLoaded: (isLoaded: boolean) => dispatch(setIsLoaded(isLoaded)),
  };
};

굳굳 근데 함수이름 다르게 해야겠네

 

 

4) thunk

import thunk from 'redux-thunk';

export const {setIsLoadedReducer} = slice.actions; // 아까 만들어준거

export const setIsLoadedAsync = (isLoaded: boolean) => { // 비동기 처리 위함
  return async (dispatch, getState) => {
    try {
      dispatch(setIsLoadedReducer);
    } catch (error) {
      // notiE
    }
  };
};

-----

const mapDispatchToProps = dispatch => {
  return {
    setIsLoadedAsync: (isLoaded: boolean) =>
      dispatch(setIsLoadedAsync(isLoaded)),
  };
};

 

이렇게 쓰면 됩니다~ 굳굳굳굳굳

 

 

 

- 강의

 

https://academy.nomadcoders.co/courses/enrolled/235420

불러오는 중입니다...

#1.0 Vanilla Counter

- 왜 리덕스를 쓰는지 알아야 해

- react-native 앱 생성

 

- count 바뀌었다고 알려주기 위해 함수 쓴다는 자체가 리덕스 쓰는 멋진 이유???????

- 다음엔 아주 심플한 리덕스로 대체할거임

 

#1.1~4 Store and Reducer / Actions / Subscriptions / Recap Refactor

- 설치

npm install redux
or
yarn add redux

 

- createStore

data를 넣을 수 있는 장소 생성.

data를 관리해주기 위해 만들어짐.

reducer를 매개변수로 받아야 함

 

- reducer

data를 modify하는 함수.

 

const reducer = () => {
    return 'hello' // 이게 data가 될거야.
};

const store = createStore(reducer);

 

reducer 콘솔 찍어보면 이렇다

 

const countModifier = () => {
  return 'hello'; // 이게 data가 될거야.
};

const countStore = createStore(countModifier);
console.log(countStore.getState()); // hello

 

어떤 함수도 count를 변경할 수 없어. reducer = data modifier만이 할 수 있다.

그 reducer는 initial state, action을 받는다.

 

action 콘솔 찍어보니 이렇다

 

이제 reducer에게 말하는 방법을 알아야 해.

 

 

 

const countModifier = (state = 0, action) => {
  console.log('state action', state, action);
  return state; // 이게 data가 될거야.
};

const countStore = createStore(countModifier);
countStore.dispatch({type: 'HELLO'});

그러면 콘솔로 찍은 action에는 dispatch해준 {type: 'HELLO'}가 찍힌다.

 

.dispatch 하면 reducer에서 액션을 찾을거야

이게 리듀서에게 메세지 보내는 방법.

 

reducer가 리턴하는건 모두 data가 됨!

subcribe: 변화를 알 수 있게 해줘

#2.0 Vanilla ToDo

- dd

NEVER MUTATE STATE. state는 read-only. 액션으로만 바꿀 수 있지.

상태를 수정하는 것이 아니라 새로운 object를 리턴하는거래.

not push(action.text) 그냥 새로운 object 리턴.

 

id: Date.now()

 

- actionCreatetors

 

#2.3 Delete To Do

- splice 대신 filter를 써라! state를 mutate하지말고 새로운 array를 반환하는 filter를~

- 나느 newArray를 만들었었는데 filter가 훨씬 간단하네?

 

- redux is just state. nodejs에서도 쓸 수 있어

 

- NEVER MUTATE STATE

#3.0 Setup

- 추가 설치

yarn add react-redux

react 에서 렌더링하기 위해 필요.

 

import {Provider} from 'react-redux';
import {store} from './src/store';

const App = () => {
  return (
    <Provider store={store}>

 

#3.2 mapStateToProps

- 내 컴포넌트에 store를 연결시켜줘

- store.getState() //state 가져오기 or store.dispatch() // 메세지 전달

 

- connect는 react와 쓰기 위해 하는거지!!! 그래서 react-redux 깔았고.

#4.1 Redux Toolkit

yarn add @reduxjs/toolkit

 

https://github.com/daheeahn/vanilla-redux/commit/dc5b1bc9a104590738a98d1f5915b34824f756e5

 

#4.1 createAction · daheeahn/vanilla-redux@dc5b1bc

Permalink Browse files #4.1 createAction Loading branch information Showing 1 changed file with 21 additions and 17 deletions. +21 −17 src/Store.ts @@ -1,31 +1,35 @@ import {createStore} from 'redux'; import {createAction} from '@reduxjs/toolkit'; export c

github.com

 

 

와우 코드 양 엄청 줄은거 보이지?

payload 기억하고~

 

#4.2 createReducer

- mutate state or return new state obj

기억하자!!!

https://github.com/daheeahn/vanilla-redux/commit/5ac7deb25bfc483bcfc33dd74ee8b2915beb1ead

 

#4.2 createReducer · daheeahn/vanilla-redux@5ac7deb

Permalink Browse files #4.2 createReducer Loading branch information Showing 1 changed file with 27 additions and 22 deletions. +27 −22 src/Store.ts @@ -1,5 +1,5 @@ import {createStore} from 'redux'; import {createAction} from '@reduxjs/toolkit'; import {c

github.com

 

 

#4.3 configureStore

- 함수이고 아줄 쿨한 미들웨어와 함께 store 생성

 

dispatcher에 payload 추가해주면 tool 안에서도 state를 추가할 수 있지

go to chart. airbnb의 state를 볼 수도 있다;;;;;;;;;;;

 

redux 툴 사용위해 toolkit은 필요없어

 

https://medium.com/encored-technologies-engineering-data-science/react-native-%EB%94%94%EB%B2%84%EA%B9%85-%ED%99%98%EA%B2%BD-%EB%A7%8C%EB%93%A4%EA%B8%B0-7e46bfe89f6

 

리액트 네이티브 디버깅 [React Native Debugging]

리액트 네이티브 초보자를 위한 디버거 사용법

medium.com

디버깅 툴 설치

 

middleware는 비워놓으면 됨

+ npm install -d react-devtools (이거는 뭐지? 음 필요하면 설치)

 

 

redux thunk도 적용했음

https://github.com/daheeahn/vanilla-redux/commit/a74d38d5789bdb8ae19cb5739123eacf02ccd0d1

 

chore: apply redux-thunk & add redux dev-tools · daheeahn/vanilla-redux@a74d38d

Permalink Browse files chore: apply redux-thunk & add redux dev-tools Loading branch information Showing 6 changed files with 280 additions and 10 deletions. +166 −0 package-lock.json +5 −1 package.json +33 −3 src/Store.ts +2 −2 src/components/ToDo.tsx +2

github.com

#4.4 createSlice

- 더더욱 간결하게

https://github.com/daheeahn/vanilla-redux/commit/96bb452cf8466d7df360e9fffdb03101f9f68fb7

 

#4.4 createSlice · daheeahn/vanilla-redux@96bb452

Permalink Browse files #4.4 createSlice Loading branch information Showing 1 changed file with 41 additions and 25 deletions. +41 −25 src/Store.ts @@ -1,13 +1,13 @@ import {Alert} from 'react-native'; import {createStore, compose, applyMiddleware} from 're

github.com