zoaseo
To Infinity And Beyond
zoaseo
전체 방문자
오늘
어제
  • 분류 전체보기 (763)
    • 개발이 좋아서 (381)
      • SAP가 좋아서 (3)
      • Java가 좋아서 (42)
      • Spring이 좋아서 (50)
      • JPA가 좋아서 (0)
      • QueryDSL이 좋아서 (26)
      • Docker가 좋아서 (7)
      • Redis가 좋아서 (7)
      • AWS가 좋아서 (5)
      • CI/CD가 좋아서 (6)
      • Troubleshooting이 좋아서 (4)
      • Kotlin이 좋아서 (7)
      • SQL이 좋아서 (6)
      • HTTP가 좋아서 (21)
      • JavaScript가 좋아서 (30)
      • TypeScript가 좋아서 (6)
      • Vue가 좋아서 (21)
      • Flutter가 좋아서 (61)
      • React가 좋아서 (20)
      • Redux(React)가 좋아서 (2)
      • Angular가 좋아서 (22)
      • HTML이 좋아서 (9)
      • CSS가 좋아서 (15)
      • PHP가 좋아서 (9)
      • Illustrator가 좋아서 (2)
    • 노력이 좋아서 (169)
    • 결과물이 좋아서 (14)
    • 코딩연습이 좋아서 (168)
      • 이론이 좋아서 (62)
      • SQL이 좋아서 (90)
    • 유용한 사이트가 좋아서 (28)
    • Github (2)

인기 글

티스토리

hELLO · Designed By 정상우.
zoaseo

To Infinity And Beyond

<step78>'redux(react)_리덕스 모듈'
노력이 좋아서

<step78>'redux(react)_리덕스 모듈'

2022. 7. 12. 10:09

1) 

counter.js 만들기

상태 number, diff

todos.js 만들기

modules/

counter.js

// 리덕스 모듈 만들기
// 1. 초기상태선언
// 2. 액션타입선언
// 3. 액션생성함수정의
// 4. 리듀서 선언

// 1. 초기상태선언
const initialState = {
    number: 0,
    diff: 1
}

// 2. 액션타입
// 다른 모듈과 액션 이름이 중복되는 것을 방지(접두사처럼 붙여준다)
const SET_DIFF = "counter/SET_DIFF";
const INCREASE = "counter/INCREASE";
const DECREASE = "counter/DECREASE";

// 3. 액션생성함수선언
// 액션생성함수는 export 키워드를 사용하여 내보내기
export const setDiff = diff => ({ type: SET_DIFF, diff });
export const increase = () => ({ type: INCREASE });
export const decrease = () => ({ type: DECREASE });

// 4. 리듀서 선언
export default function counter(state=initialState, action){
    switch(action.type){
        case SET_DIFF:
            return {
                ...state,
                diff: action.diff
            }
        case INCREASE:
            return {
                ...state,
                number: state.number + state.diff
            }
        case DECREASE:
            return {
                ...state,
                number: state.number - state.diff
            }
        default:
            return state;
    }
}

todos.js

// 리덕스 모듈 만들기
// 1. 초기상태선언
// 2. 액션타입선언
// 3. 액션생성함수정의
// 4. 리듀서 선언

// 1. 초기상태선언
const initialState = [
    // {
    //     id: 1,
    //     text: "예시",
    //     done: false
    // }
]

// 2. 액션타입선언
const ADD_TODO = 'todos/ADD_TODO';
const TOGGLE_TODO = 'todos/TOGGLE_TODO';

// 3. 액션생성함수
let nextId = 1;
export const addTodo = text => ({
    type: ADD_TODO,
    todo: {
        id: nextId++,
        text,
        done: false
    }
});
export const toggleTodo = id => ({
    type: TOGGLE_TODO,
    id
});

// 4. 리듀서 선언
export default function todos(state=initialState, action){
    switch(action.type){
        case ADD_TODO:
            return state.concat(action.todo)
        case TOGGLE_TODO:
            return state.map(
                todo =>
                todo.id === action.id ? // id가 일치하면
                { ...todo, done: !todo.done} // done값을 반전
                :todo // 아니라면 그대로 둠
            )
        default: 
        return state;
    }
}

 

2)

루트 리듀서 만들기

하나의 프로젝트에 여러개의 리듀서가 있을 때 한 리듀서로 합쳐서 사용

합쳐진 리듀서를 루트리듀서라고 합니다.

* 리덕스에 내장함수인 combineReducers()함수 사용

 

스토어 생성하기

index.js 

createStore(rootReducer)

import { combineReducers } from 'redux';
import counter from './counter';
import todos from './todos';

const rootReducer = combineReducers({
    counter,
    todos
})

export default rootReducer;
npm install react-redux // 리액트 프로젝트에 리덕스 사용하기

import { Provider } from 'react-redux'

<Provider store={store}>

    <App/>

</Provider>

* Provider로 store를 넣어서 App을 감싸게 되면

렌더링하는 그 어떤 컴포넌트에서 리덧스 스토어로 접근할 수 있음

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux';
import{ Provider } from 'react-redux';
import rootReducer from './modules';

// 스토어 만들기
const store = createStore(rootReducer);
console.log(store.getState());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
    <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

3)

1. 프리젠테이셔널 컴포넌트

리덕스 스토어에 직접적으로 접근하지 않고 필요한 값, 함수를 props로만 받아와서 사용하는 컴포넌트

2. 컨테이너 컴포넌트

리덕스 스토어의 상태를 조회하거나 액션을 디스패치할 수 있는 컴포넌트

html태그들을 사용하지 않고 프리젠테이셔널 컴포넌트를 불러와서 사용

 

components/

Counter.js

import React from 'react';

const Counter = ({number, diff, onIncrease, onDecrease, onSetDiff}) => {
    const onChange = e => {
        onSetDiff(parseInt(e.target.value))
    }
    return (
        <div>
            <h2>{number}</h2>
            <div>
                <input type="number" value={diff}
                min="1" onChange={onChange} />
                <button onClick={onIncrease}>+</button>
                <button onClick={onDecrease}>-</button>
            </div>
        </div>
    );
};

export default Counter;

CounterContainer.js

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increase, decrease, setDiff } from '../modules/counter';
import Counter from './Counter';

const CounterContainer = () => {
    // useSelector는 리덕스 스토어의 상태를 조회하는 Hook함수
    // store.getState()할 때 결과와 동일함
    const { number, diff } = useSelector(state => (state.counter));
    // {number: 0, diff: 1}
    // useDispatch는 리덕스 스토어의 dispatch를 함수에서 사용할 수 있게 해주는 Hook함수
    const dispatch = useDispatch();
    // 각 액션을 dispatch하는 함수
    const onIncrease = () => dispatch(increase());
    const onDecrease = () => dispatch(decrease());
    const onSetDiff = diff => dispatch(setDiff(diff));
    return (
        <div>
            <Counter 
            number={number} 
            diff={diff} 
            onIncrease={onIncrease}
            onDecrease={onDecrease}
            onSetDiff={onSetDiff}
            />
        </div>
    );
};

export default CounterContainer;

Todos.js

import React,{useState} from 'react';

const TodoList = ({todos, onToggle}) => {
    return (
        <ul>
            {
                todos.map(todo=>(
                    <TodoItems todo={todo} key={todo.id} onToggle={onToggle}/>
                ))
            }
        </ul>
    )
}
const TodoItems = ({todo, onToggle}) => {
    return (
        <li onClick={()=>onToggle(todo.id)}
        style={{ color: todo.done ? 'red' : 'black' }}
        >{todo.text}</li>
    )
}

const Todos = ({todos, onCreate, onToggle}) => {
    const [ text, setText ] = useState("");
    const onChange = e => {
        setText(e.target.value);
    }
    const onSubmit = e => {
        e.preventDefault(); // submit 이벤트가 발생했을 때 새로고침 방지
        onCreate(text);
        setText('');
    }
    console.log(todos);
    return (
        <div>
            <form onSubmit={onSubmit}>
                <input value={text}
                placeholder="할 일을 등록하세요."
                onChange={onChange}
                />
                <button type="submit">등록</button>
            </form>
            <TodoList todos={todos} onToggle={onToggle}/>
        </div>
    );
};

export default Todos;

TodosContainer.js

import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { addTodo, toggleTodo } from '../modules/todos';
import Todos from './Todos';

const TodosContainer = () => {
    const todos = useSelector(state => (state.todos));
    // dispatch 함수 만들기
    const dispatch = useDispatch();
    const onCreate = text => dispatch(addTodo(text));
    const onToggle = id => dispatch(toggleTodo(id));
    return (
        <div>
            <Todos todos={todos} onCreate={onCreate} onToggle={onToggle}/>
        </div>
    );
};

export default TodosContainer;

 

4)

devtools 사용하기

npm install redux-devtools-extension
import { composeWithDevTools } from 'redux-devtools-extension'
createStore(rootReducer, composeWithDevTools())

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { createStore } from 'redux';
import{ Provider } from 'react-redux';
import rootReducer from './modules';
import { composeWithDevTools } from 'redux-devtools-extension';

// 스토어 만들기
const store = createStore(rootReducer, composeWithDevTools());
console.log(store.getState());
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
    <App />
    </Provider>
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

 

'노력이 좋아서' 카테고리의 다른 글

<step80>'redux(react)_리덕스 미들웨어'  (0) 2022.07.14
<step79>'react_팀 프로젝트 진행'  (0) 2022.07.13
<step78>'redux(react)_기초2'  (0) 2022.07.12
<step77>'redux(react)_기초'  (0) 2022.07.11
<step76>'react_고객관리 사이트 구현_step_final'  (0) 2022.07.08

    티스토리툴바