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 |