기본 콘텐츠로 건너뛰기

vulcanJS - 10. Posts Update/Delete

마지막으로 수정과 삭제를 구현해보면 목록 조회(List), 상세 조회, 쓰기, 수정, 삭제까지 모든 필요한 요소를 아우를 수 있을 것이다.
감이 좋은 분들은 눈치 챘을지도 모르겠지만 사실 수정이란 건 UI면에서 볼때 이미 양식이 채워져있는 신규 쓰기와 별반 다르지 않다.

먼저 해야할 것은 역시나 Component를 만드는 일이다.
$ vulcan g component
? Package name spectrum-simplebb
? Component name PostsEditComponent
? Component type Class Component
? Register component Yes
   create packages/spectrum-simplebb/lib/components/PostsEditComponent.jsx
 conflict packages/spectrum-simplebb/lib/components/index.js
? Overwrite packages/spectrum-simplebb/lib/components/index.js? overwrite
    force packages/spectrum-simplebb/lib/components/index.js
PostsEditComponent를 만들었다.
route도 만들자. /posts/edit/:id 이렇게 경로를 만들면 좋겠다. 그러고보니 이전 글에서 만든 상세보기도 /posts/view/:id 형식으로 만들껄 그랬다.
$ vulcan g route
? Package name spectrum-simplebb
? Route name postsEdit
? Route path /posts/edit/:_id
? Component name PostsEditComponent
? Layout name
 conflict packages/spectrum-simplebb/lib/modules/routes.js
? Overwrite packages/spectrum-simplebb/lib/modules/routes.js? overwrite
    force packages/spectrum-simplebb/lib/modules/routes.js
Route도 만들었다.

그렇다면 다음은 /posts/edit/:_id로 들어올 진입점을 만들자. PostsSingleComponent가 괜찮아보인다.
<Link to={`/posts/edit/${this.props.documentId}`}>Edit</Link>
이 부분을 삽입하여주자.
import React, { Component } from 'react';
import { Link } from 'react-router';
import { registerComponent, withDocument } from 'meteor/vulcan:core';
import Posts from "../modules/posts/collection.js";
class PostsSingleComponent extends Component {
  render () {
    return (
      this.props.loading &&
        <div />
      ||
        <div>
          <h1>{this.props.document.title}</h1>
          <pre>
            {this.props.document.body}
          </pre>
          <div>
            <Link to={`/posts/edit/${this.props.documentId}`}>Edit</Link>
          </div>
          <div>
            <Link to='/'>to Home</Link>
          </div>
        </div>
    );
  }
}
registerComponent('PostsSingleComponent', PostsSingleComponent, [withDocument, {
  collection: Posts
}]);
export default PostsSingleComponent;
상위 Component인 PostsViewComponent가 _id를 documentId로 전달하므로 같은 걸 사용했다.
목록>상세>수정까지 진입하는 길은 다 만들어졌다.
수정 서식을 보여주도록 PostsEditComponent를 고쳐보자.

사실 PostsEditComponent는 PostsNewComponent와 거의 같다.
단 하나 차이점이 있다면 SmartForm에 documentId를 지정하는 것만이 다르다.
즉, SmartForm Component는 documentId를 지정할 경우 수정을 하고 없을 경우 새로운 Document를 생성한다고 보면된다.
import React, { Component } from 'react';
import { registerComponent, Components } from 'meteor/vulcan:core';
import Posts from  "../modules/posts/collection.js";
class PostsEditComponent extends Component {
  render () {
    return (
      <div>
        <Components.SmartForm
          collection={Posts}
          documentId={this.props.params._id}
        />
      </div>
    );
  }
}
registerComponent('PostsEditComponent', PostsEditComponent);
export default PostsEditComponent;
날로 먹는다고 봐야 한다.
아직 날로 먹는 건 끝이 아니다.
SmartForm은 collection과 documentId 말고도 몇 가지가 더 있기 때문이다.

지금 현재 구현은 수정이라는 기능엔 충실하지만 실제로 사용자는 수정을 완료한 뒤에 멀뚱하게 그자리에 있는 것을 원하지 않을 것이다.
successCallback을 추가하여 수정 완료 시 상세 조회 화면으로 돌아가도록 해 보자.
import React, { Component } from 'react';
import { registerComponent, Components } from 'meteor/vulcan:core';
import Posts from  "../modules/posts/collection.js";
class PostsEditComponent extends Component {
  render () {
    return (
      <div>
        <Components.SmartForm
          collection={Posts}
          documentId={this.props.params._id}
          successCallback={
            ()=> this.props.router.push(`/posts/${this.props.params._id}`)
          }
        />
      </div>
    );
  }
}
registerComponent('PostsEditComponent', PostsEditComponent);
export default PostsEditComponent;
router객체 안에 있는 push를 사용하여 해당 글로 다시 돌아가보았다.
신규 작성에 비해 수정을 위해서 우리가 해준 건 딱 두개 밖에 없다.
  1. documentID 를 추가했고
  2. 수정 후 callback을 구현했다.
그러면 이젠 마지막 관문인 삭제 구현을 해야하는데 이게 의외로 싱겁다.
SmartForm에 속성 두개만 추가하면 된다.
  1. showRemove={true} 를 추가하여 삭제 기능을 화면에 보여주고
  2. removeSuccessCallback을 구현하여 삭제 후 callback을 구현하면 된다.
한번 해보자.
먼저 removeSuccessCallback 후엔 이미 자신이 사라진 이후니까 successCallback처럼 자신의 글로 되돌아 갈 수 없다.
목록으로 가도록 해주자.
          removeSuccessCallback ={
            ()=> this.props.router.push(`/`)
          }
이 정도가 적당할 것 같다.
전부 모아보자.
import React, { Component } from 'react';
import { registerComponent, Components } from 'meteor/vulcan:core';
import Posts from  "../modules/posts/collection.js";
class PostsEditComponent extends Component {
  render () {
    return (
      <div>
        <Components.SmartForm
          collection={Posts}
          documentId={this.props.params._id}
          successCallback={
            ()=> this.props.router.push(`/posts/${this.props.params._id}`)
          }
          showRemove={true}
          removeSuccessCallback ={
            ()=> this.props.router.push(`/`)
          }
        />
      </div>
    );
  }
}
registerComponent('PostsEditComponent', PostsEditComponent);
export default PostsEditComponent;
showRemove와 removeSuccessCallback을 구현하였다.


Delete 기능이 아래 달라붙었다.
버튼 같지 않지만 그거야 스타일링 하면 되고 클릭해보자.
확인 alert이 뜨고.
홈으로 이동 후 삭제가 잘 이루어졌다.
갑자기 수정/삭제가 너무 허망하게 구현이 된 것 같은 느낌은 있지만 여기까지 필요한 최소한의 기능은 모두 구현해보았다고 할 수 있다.

이제 나머지는 디테일을 위한 공부!


Vulcan 메뉴얼은 당연히 읽고

Meteor 도 봐두고

GraphQL도 익히고

React도 보고

즐거운 공부 뿐이다. 즐기자.

이 블로그의 인기 게시물

meteor로 nw.js 개발하기.

실제로 nw.js 어플리케이션을 개발하다보면 UI구현하기 막막하고 수동으로 리프레쉬 하는 것도 귀찮아서 Meteor 연동을 하려고 했더니 생각보다 간단했다.

디렉토리 구조는 먼저 이렇게 잡았다.
`- app
  `-client
  `-public
`- dist
  `- 배포용 html,css,js
  `- package.json
`- package.json 아이디어는 이렇다. nw.js의 시작페이지를 http://localhost:3000으로 두고 배포시엔 meteor client 배포툴인 meteor-build-client를 사용하여 html,css,js 로 분리하는 계획이다.

가장 중요한 nw.js 용 package.json 파일은 아래와 같이 구성한다.
{
  "main": "http://localhost:3000",
  "node-remote": "http://localhost:3000",
  "name": "<앱이름>"
} 이게 전부. 어떻게 보면 Web과 nw.js를 동시에 개발할 수도 있는 환경이기도 한 것이다.
meteor create app 을 해서 meteor용 앱을 만들고 meteor 를 시작한다.
그리고, 위의 package.json이 있는 경로로 돌아가서 nw . 으로 nwjs를 실행한다.

한번 번쩍하더니 잘 된다.
cordova 등에서 index.html 대신 http://localhost:3000을 하는 것도 비슷한 느낌이다.

즐겁게 개발을 일단 마구 하고 실제로 배포하기 위해서는 개발환경이 아니라 html,css,js로 구성된 배포본을 만들어야한다.
npm install -g 해도 되지만 어짜피 Meteor에서만 쓸거
meteor npm install -g meteor-build-client 해버릴거다.

개발은 문제 없어 보이고 배포판을 한번 만들어보자. meteor app 이 있는 경로(meteor run으로 …

RxJS - ReactiveX 인터뷰

A: 왜 RxJS입니까
B: javascript는 참 쉽고 친숙한 언어죠.
A: 별로 그렇게 생각 안합니다만.
B: 그래서 좀 어렵고 있어보이는게 뭘까 싶어서...
A: 네?
B: 함수형이라는게 유행하기도 하고
f(x) 좋쟎습니까? 미스테리~ 미스테리~ 정수정짱짱 으아아

이런 수학선생님이라면 수포자 따윈 A: ...
B: 그리고 반응형이라는 말 뭔가
A: 뭔가?
B: 대충대충해도 막 알아서 할거 같고...
A: 그럴리가요?
B: 안그렇겠죠?
A: 네
B: 네

(잠시만 기다려주세요)

A: 그래도 뭔가 매력이 있으니 이렇게 시간을 내셔서 이것저것 Rx에 대해 글도 쓰고 이야기도 하고 그러시는거 아닌가요?
B: 매력이라.
으음.
제가 팔꿈치 터널 증후근이 좀 있어요.
오른손 세끼손가락, 약지손가락이 저립니다.
A: 무슨 상관이?
B: 그래서 각종 괄호를 쓰는게 너무 힘듭니다.
소중대괄호 만든 사람 죽었으면.
Hello world (ASCII): https://esolangs.org/wiki/Parenthesis_Hell
A: 이미 옛날에 돌아가셨겠죠.
B: 그렇겠네요.
아무튼 그래서 소중대괄호 의존이 적은 커피스크립트를 쓰는데요.
A: 빨리 본론을 말씀해주시죠.
B: 커피스크립트에서 가로로 80자 이상쓰면 Line exceeds maximum allowed length 라고 경고해요.
A: 그래서요?
B: 근데 Rx를 쓰면 코드를 가늘게 쓸 수가 있더라구요.
A: 호오?
B: 그리고 = 쓰는 것도 너무 힘듭니다.
A: 네?
B: 오른손을 쓰쟎아요.
A: ...
그러니까 정리하면
1. 괄호가 힘들다
2. 커피를 쓴다
3. 커피는 길게 쓰면 경고
4. Rx를 쓰면 코드가 가늘다
5. 대입문을 줄이고 싶다.
B: 네
하지만 5번은 생각보다 별로...
A:
B:

B: 아!
A: ?
B: 코드가 가늘어서 좋은 점이.
A: 네.
B: 핸드폰에서 코드를 보기 좋습니다.
A: ... 왜 팔꿈치 터널 증후근이 안 낫는지 알겠습니다.
B: 도와주세요.
쇠고기 사묵으면 나을 것 같습니…

Troubleshooting - Meteor package가 적용이 되지 않을 때

버전 1.5 기준 package.js에서 Package.onUse 에 새 패키지를 추가했는데 인식하지 못하는 경우가 있다.
Package.onUse((api) => {
  api.use([
    'vulcan:core',
    'vulcan:forms',
    'vulcan:accounts' /* <-- 추가함! */
  ]);
...
} 내부패키지건 원격패키지건 안되는 안된다. 이럴 때 meteor add 후 meteor remove 해도 되지만 더 간단한 방법이 있다. meteor update vulcan:accounts 이렇게 update 해주는 방법이 있다. .meteor/package 파일을 건들지 않아서 좋다. 그래도 역시 좋지 않다. Meteor 스럽지 않다. https://github.com/meteor/meteor/issues/7721 현재 1.5.2에서도 해결이 안되었군요. 해결되어 적용되면 다시 글 올리겠습니다.