본문 바로가기
개발(라이브러리,프레임워크)/react.js & react native

Redux 개요, 사용

by zieunee 2022. 1. 20.
반응형

npm i redux

Action

  • 액션은 그냥 객체이다.
  • 두가지 형태의 액션
    • { type : ‘TEST’} // payload없는 액션
    • { type: ‘TEST’, params : ‘hello’ } // payload 있는 액션
  • type만이 필수 프로퍼티이며, type은 문자열이다.

액션 생성자

사용 방법

function 액션 생성자(...args) { return 액션; }
  1. 액션 생성자를 통해 액션을 만들어 낸다.
  2. 만들어낸 액션 객체를 redux store에 보낸다.
  3. redux store가 액션 객체를 받으면 스토어의 상태 값이 변경된다.
  4. 변경된 상태 값에 의해 상태를 이용하고 있는 컴포넌트가 변경된다.
  5. 액션은 스토어에 보내는 일종의 인풋

액션 객체 만들기 action.js

export const ADD_TODO = "ADD_TODO"

export function addTodo(todo) {
    return {
        type: ADD_TODO,
        todo,
    };
}
//action 객체 생성

Reducers

  • 액션을 주면 액션이 적용되어 수정된 결과를 만들어 준다.
  • 순수 함수 (pure Function) 이다.
    • immutable > reducer를 통해서 state가 달라졌다는걸 redux가 인지하는 방식이다.

사용 방법

function 리듀서(previousState, action) {
    return newState;
}

action을 받아서 state를 리턴

인자로 들어온 previousState와 리턴되는 newState는 다른 참조를 가져야 한다.

리듀서 만들기 reducers.js

import { ADD_TODO } from './actions';

//state 구상하자면 ?
// ['하이','난 지니'];
const initialState = [];
export function todoApp(previousState = initialState, action) {
    //초기값 지정 해주는 부분 >> '= initialState'으로 대체
    // if(previousState === undefined){
    //     return [];
    // }
    if(action.type === ADD_TODO){
        return [...previousState, action.todo];
    }

    return previousState;
}

createStore

const store = createStore(리듀서);
//인자 3개
createStore(reducer함수, preloadedState,enchancer);
import { createStore } from 'redux'
import { todoApp } from './reducers'

const store = createStore(todoApp);
export default store;

storeindex.js에서 출력해보면?

dispach, getState 등등의 값이 나온다.

getState : 현재의 state의 상태

dispatch: action을 인자로 가지고 있음

index.js

const unsubscribe = store.subscribe(() => {
  console.log(store.getState());
})
console.log(store);
store.dispatch(addTodo('jieun'));
unsubscribe();
store.dispatch(addTodo('hihi'));

subscribe

  • 스토어의 변경사항 생기는 것을 구독!
  • 스토어 상태 변경되면 호출된다.
  • 함수는 리턴이 함수인데 호출을 하면 더 이상 subscribe 함수에 출력되지 않는다.

store 정리

  • store.getState();
    • 현재 state를 가져옴
  • store.dispatch(액션); / store.dispatch(액션생성자());
  • const unsubscribe = store.subscribe(()⇒{});
    • 리턴이 unsubscribe이다.
    • unsubscribe()하면 제거된다.
  • store.replaceReducer(다른리듀서);
    • 원래 리듀서를 다른 리듀서로 바꾼다. > 잘 안쓰임

combineReducers

 

객체로 전달된 state값들중 하나를 false> true 로 변경하는 작업 해보기

state 형태

{
    todos: [{text: '공부' , done: false}, {text}: '점심' , done: true}] ,
    filter: 'ALL'
}

acions.js

export const ADD_TODO = "ADD_TODO"
export const COMPLETE_TODO = 'COMPLETE_TODO';

// {type : ADD_TODO , text: '할일'}
export function addTodo(text) {
    return {
        type: ADD_TODO,
        text,
    };
}
// {type : COMPLETE_TODO , index: 3} > 완성된 index 값
export function completeTodo(index) {
    return {
        type: COMPLETE_TODO,
        index,
    };
}
export const SHOW_ALL = 'SHOW_ALL';
export const SHOW_COMPLETE = 'SHOW_COMPLETE';

export function showAll() {
    return {type:SHOW_ALL};
}
export function showComplete() {
    return {type: SHOW_COMPLETE,};
}

reducers.js

import { ADD_TODO, COMPLETE_TODO , SHOW_COMPLETE , SHOW_ALL } from './actions';

//state 구상
//{
//todos: [{text: '공부' , done: false}, {text}: '점심' , done: true}] ,
//filter: 'ALL'
//}
// 객체로 변경 
const initialState = { todos: [] , filter: 'ALL' };
export function todoApp(previousState = initialState, action) {
    if(action.type === ADD_TODO){
        return {
            ...previousState,
            todos: [...previousState.todos, {text: action.text, done: false}],
        };
    }
    if(action.type === COMPLETE_TODO){
        return {
            ...previousState,
            todos: previousState.todos.map((todo, index) => {
            if(index === action.index){
                return {...todo, done: true};
            }
            return todo;
        })};
    }
    if(action.type === SHOW_COMPLETE){
        return {
            ...previousState,
            filter : "COMPLETE",
        };
    }
    if(action.type === SHOW_ALL){
        return {
            ...previousState,
            filter : "ALL",
        };
    }

    return previousState;
}

store.js

import { createStore } from 'redux'
import { todoApp } from './reducers'

const store = createStore(todoApp);
export default store;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import store from './redux/store';
import { addTodo, completeTodo, showAll, showComplete } from './redux/actions'

//스토어의 변경사항 생기는 것을 구독!
//스토어 상태 변경되면 호출된다.
store.subscribe(() => {
  console.log(store.getState());
})

store.dispatch(addTodo('할일'));
store.dispatch(completeTodo(0));
store.dispatch(showComplete());
store.dispatch(showAll());

reducer > 단일 스토어여서 여러개 둘수도 없고, 복잡해진다. 그래서 쪼개서 작업 하기

이것을 도와주는게 combineReducer 이다.

reducers.js

import { ADD_TODO, COMPLETE_TODO , SHOW_COMPLETE , SHOW_ALL } from './actions';
import { combineReducers } from 'redux'
//state 구상
//{
//todos: [{text: '공부' , done: false}, {text}: '점심' , done: true}] ,
//filter: 'ALL'
//}
// 객체로 변경 
const initialState = { todos: [] , filter: 'ALL' };
const todosInitialState = initialState.todos;
const filterInitialState = initialState.filter;

const reducer = combineReducers({
    todos: todosReducer,
    filter: filterReducer
})
export default reducer;

//todos: [{text: '공부' , done: false}, {text}: '점심' , done: true}]
export function todosReducer(previousState = todosInitialState, action) {
    if(action.type === ADD_TODO){
        return [...previousState, {text: action.text, done: false}];
    }
    if(action.type === COMPLETE_TODO){
        return previousState.map((todo, index) => {
            if(index === action.index){
                return {...todo, done: true};
            }
            return todo;
        });
    }

    return previousState;
}

//filter: 'ALL'
function filterReducer(previousState = filterInitialState, action) {
    if(action.type === SHOW_COMPLETE){
        return "COMPLETE";
    }
    if(action.type === SHOW_ALL){
        return "ALL";
    }

    return previousState;
}

stores.js

import { createStore } from 'redux'
import todoApp from './reducers'

const store = createStore(todoApp);
export default store;

요래 수정하기

더 간결하게 만들기 (파일 분리)

이렇게 파일 분리하기

reducer.js

import { combineReducers } from 'redux'
import todos  from './todos'
import filter  from './filter'
const reducer = combineReducers({
    todos,
    filter
})

export default reducer;

todos.js

import { ADD_TODO, COMPLETE_TODO } from '../actions';

const initialState =  [] 

export default function todos(previousState = initialState, action) {
    if(action.type === ADD_TODO){
        return [...previousState, {text: action.text, done: false}];
    }
    if(action.type === COMPLETE_TODO){
        return previousState.map((todo, index) => {
            if(index === action.index){
                return {...todo, done: true};
            }
            return todo;
        });
    }

    return previousState;
}

filter.js

import {  SHOW_COMPLETE , SHOW_ALL } from '../actions';

const initialState = 'ALL';

export default function filter(previousState = initialState, action) {
    if(action.type === SHOW_COMPLETE){
        return "COMPLETE";
    }
    if(action.type === SHOW_ALL){
        return "ALL";
    }

    return previousState;
}

store.js

import { createStore } from 'redux'
import todoApp from './reducers/reducer'

const store = createStore(todoApp);
export default store;

완성~

반응형

'개발(라이브러리,프레임워크) > react.js & react native' 카테고리의 다른 글

Async Action  (0) 2022.01.31
Redux 를 React에 연결(라이브러리x)  (0) 2022.01.21
Hooks  (0) 2022.01.09
라우팅  (0) 2021.09.26
컴포넌트  (0) 2021.09.24