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: [],
// 에러 관련 state 등록.
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: ""
}
};

하루를 기록하다