React & Django 프로젝트
input태그를 이용하여 직관적으로 한줄 노트를 작성할수 있는 앱
R&D Note - NewDnote (새글 쓰기)
store/modules/notes.js
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
| import { ajax } from "rxjs/observable/dom/ajax"; import { of } from "rxjs"; import { map, mergeMap, catchError, withLatestFrom } from "rxjs/operators"; import { ofType } from "redux-observable";
const CHANGE_NOTE_INPUT = "notes/CHANGE_NOTE_INPUT";
const ADD_NOTE = "notes/ADD_NOTE"; const ADD_NOTE_SUCCESS = "notes/ADD_NOTE_SUCCESS"; const ADD_NOTE_FAILURE = "notes/ADD_NOTE_FAILURE";
export const changeNoteInput = ({ value }) => ({ type: CHANGE_NOTE_INPUT, payload: { value } });
export const addNote = () => ({ type: ADD_NOTE }); export const addNoteSuccess = note => ({ type: ADD_NOTE_SUCCESS, payload: { note } }); export const addNoteFailure = error => ({ type: ADD_NOTE_FAILURE, payload: { error } });
const addNoteEpic = (action$, state$) => { return action$.pipe( ofType(ADD_NOTE), withLatestFrom(state$), mergeMap(([action, state]) => { return ajax.post(`/api/notes/`, { text: state.notes.noteInput }).pipe( map(response => { const note = response.response; return addNoteSuccess(note); }), catchError(error => of({ type: ADD_NOTE_FAILURE, payload: error, error: true }) ) ); }) ); };
const initialState = { noteInput: "", notes: [] };
export const notes = (state = initialState, action) => { switch (action.type) { case CHANGE_NOTE_INPUT: return { ...state, noteInput: action.payload.value }; case ADD_NOTE_SUCCESS: const { note } = action.payload; return { ...state, notes: [note].concat(state.notes), noteInput: "" }; case ADD_NOTE_FAILURE: return { ...state, error: { triggered: true, message: "Error! Please Try With Unempty Note" } }; default: return state; } };
export const notesEpics = { addNoteEpic };
|
위와 같이 note를 추가하는 epic과 액션, 리듀서들을 생성해주세요.
그리고, index.js에서 epic을 반영해주세요.
modules/index.js
1 2 3 4 5 6
| import { notes, notesEpics } from "./notes"; import { combineReducers } from "redux"; import { combineEpics } from "redux-observable";
export const rootReducers = combineReducers({ notes }); export const rootEpics = combineEpics(notesEpics.addNoteEpic);
|
처음으로 epic이 나왔는데요, 이 epic은 configure에서 다음과 같이 등록해주어야 사용할수 있습니다.
store/configure.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import { createStore, applyMiddleware, compose } from "redux"; import { createEpicMiddleware } from "redux-observable";
import { rootReducers, rootEpics } from "./modules";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const epicMiddleware = createEpicMiddleware();
export default createStore( rootReducers, composeEnhancers(applyMiddleware(epicMiddleware)) );
epicMiddleware.run(rootEpics);
|
이제 container로 다시 돌아와서 다음 작업들을 해줘야합니다.
containers/NoteContainer.js
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 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| import React, { Component } from "react"; import { connect } from "react-redux"; import InsertForm from "../components/notes/InsertForm"; import NoteWrapper from "../components/notes/NoteWrapper";
import * as noteActions from "../store/modules/notes";
export class NoteContainer extends Component { handleChange = ({ value }) => { const { changeNoteInput } = this.props; changeNoteInput({ value }); };
addNote = () => { const { addNote } = this.props; addNote(); };
render() { const { noteInput } = this.props; const { handleChange, addNote } = this; return ( <div> <NoteWrapper> <InsertForm noteInput={noteInput} onChangeInput={handleChange} onAdd={addNote} /> </NoteWrapper> </div> ); } }
const mapStateToProps = state => ({ noteInput: state.notes.noteInput, notes: state.notes.notes });
const mapDispatchToProps = dispatch => { return { changeNoteInput: ({ value }) => { dispatch(noteActions.changeNoteInput({ value })); }, addNote: () => { dispatch(noteActions.addNote()); } }; };
export default connect( mapStateToProps, mapDispatchToProps )(NoteContainer);
|
components/notes/InsertForm/InsertForm.js
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
| import React from "react"; import styles from "./InsertForm.scss"; import classNames from "classnames/bind";
const cx = classNames.bind(styles);
const InsertForm = ({ noteInput, onChangeInput, onAdd }) => { const handleChange = e => { const { value } = e.target; onChangeInput({ value }); };
const handleKeyPress = e => { if (e.key === "Enter") { onAdd(); } };
return ( <div className={cx("form")}> <div className={cx("title")}>Insert Your Note Here...</div> <input type="text" name="note" value={noteInput} onChange={handleChange} onKeyPress={handleKeyPress} /> </div> ); };
export default InsertForm;
|
근데 이상태로는 오류가 납니다, 이유는 proxy
설정을 안했기 때문인데요, package.json에서 프록시 설정을 해줍니다.
package.json
1
| "proxy": "http://localhost:8000"
|
자 이제 엔터를 치면 노트가 생성됨을 알수 있습니다.
크롬 개발자도구를 키고, network에서 보시면 201 생성이 뜨죠?
에러 처리
modules/notes.js
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
| const initialState = { noteInput: "", notes: [], error: { triggered: false, message: "" } }; containers/NoteContainer.js
...
render() { const { noteInput, error } = this.props; const { handleChange, addNote } = this; return ( <div> <NoteWrapper> <InsertForm noteInput={noteInput} onChangeInput={handleChange} onAdd={addNote} error={error} /> </NoteWrapper> </div> ); }
...
const mapStateToProps = state => ({ noteInput: state.notes.noteInput, notes: state.notes.notes, error: state.notes.error });
|
components/notes/InsertForm/InsertForm.js
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 38
| import React from "react"; import styles from "./InsertForm.scss"; import classNames from "classnames/bind";
const cx = classNames.bind(styles);
const InsertForm = ({ noteInput, onChangeInput, onAdd, error }) => { const handleChange = e => { const { value } = e.target; onChangeInput({ value }); };
const handleKeyPress = e => { if (e.key === "Enter") { onAdd(); } };
return ( <div className={cx("form")}> <div className={cx("title")}>Insert Your Note Here...</div> <div className={cx("error")}> {error.triggered && ( <div className={cx("message")}>{error.message}</div> )} </div> <input type="text" name="note" value={noteInput} onChange={handleChange} onKeyPress={handleKeyPress} /> </div> ); };
export default InsertForm;
|
이제 에러가 생기면 반영이 됩니다. 그러나 제대로 입력했을때도 남아있으니, 이부분을 고쳐보겠습니다.
store/modules/notes.js
1 2 3 4 5 6 7 8 9 10 11 12
| case ADD_NOTE_SUCCESS: const { note } = action.payload; return { ...state, notes: [note].concat(state.notes), noteInput: "", error: { triggered: false, message: "" } };
|
하루를 기록하다