References: Creating your first app



이번엔 User Account를 추가해 봅니다.



1. 유저 기능 추가하기



미티어 프레임 워크에서 제공해주는 accounts-ui와 accounts-password 패키지를 사용합니다.


콘솔에서 다음 명령을 실행합니다: meteor add accounts-ui accoutns-password



accounts-ui는 블레이즈 UI 컴포넌트이므로 리액트에서 사용하기 위해 래핑해줍니다.


/imports/ui/AccountsUIWrapper.jsx


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import { Template } from 'meteor/templating';
import { Blaze } from 'meteor/blaze';
 
export default class AccountsUIWrapper extends Component {
  componentDidMount() {
    // Use Meteor Blaze to render login buttons
    this.view = Blaze.render(Template.loginButtons,
      ReactDOM.findDOMNode(this.refs.container));
  }
  componentWillUnmount() {
    // Clean up Blaze view
    Blaze.remove(this.view);
  }
  render() {
    // Just render a placeholder container that will be filled in
    return <span ref="container" />;
  }
}
cs


래퍼를 사용하도록 /imports/ui/app.jsx파일을 수정해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Tasks } from '../api/tasks.js';
import ReactDOM from 'react-dom';
import Task from './Task';
import AccountsUIWrapper from './AccountsUIWrapper.jsx';
...
            ...
            Hide Completed Tasks
          </label>
          <AccountsUIWrapper />
          <form className="new-task" onSubmit={this.handleSubmit.bind(this)} >
            <input
                ...
 
cs


accounts-ui의 기본 id포맷은 email입니다. 이걸 변경할 수 있도록 설정을 추가합니다.


/imports/startup/accounts-config.js


1
2
3
4
5
import { Accounts } from 'meteor/accounts-base';
 
Accounts.ui.config({
  passwordSignupFields: 'USERNAME_ONLY'
});
cs


추가한 설정 파일을 적용합니다.


/clinet/main.jsx


1
2
3
4
5
6
7
8
9
10
11
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
 
import App from '../imports/ui/App';
import '../imports/startup/accounts-config.js';
 
Meteor.startup(() => {
  render(<App />document.getElementById('render-target'));
});
 
cs


이후 화면을 확인하면 Sing in이 추가된 것을 확인할 수 있으며 이를 클릭하면 다음과 같은 화면이 출력됩니다.





2. 작업 목록에 유저 기능 적용하기.



이제 작업 목록에 유저에 대한 정보를 적용 시켜 보겠습니다.

** owner: 작업을 작성한 사용자의 _id

** username: 작업을 작성한 사용자의 이름.


/imports/ui/App.jsx


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
import React, { Component } from 'react';
import { withTracker } from 'meteor/react-meteor-data';
import { Tasks } from '../api/tasks.js';
import ReactDOM from 'react-dom';
import Task from './Task';
import AccountsUIWrapper from './AccountsUIWrapper.jsx';
import { Meteor } from 'meteor/meteor';
 
// App component - represents the whole app
class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      hideCompleted: false,
    };
  }
 
  handleSubmit(event) {
    event.preventDefault();
    // Find the text field via the React ref
    const text = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
    Tasks.insert({
      text,
      createdAt: new Date(), // current time
      owner: Meteor.userId(),           // _id of logged in user
      username: Meteor.user().username,  // username of logged in user
    });
    // Clear form
    ReactDOM.findDOMNode(this.refs.textInput).value = '';
  }
 
...
 
export default withTracker(() => {
  return {
    tasks: Tasks.find({}, { sort: { createdAt: -1 } }).fetch(),
    incompleteCount: Tasks.find({ checked: { $ne: true } }).count(),
    currentUser: Meteor.user(),
  };
})(App);
cs


그리고 로그인 한 경우에만 새 작업을 생성할 수 있도록 합니다.


/imports/ui/App.jsx


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
...
  render() {
    return (
      <div className="container">
        <header>
        <h1>Todo List ({this.props.incompleteCount})</h1>
          <label className="hide-completed">
            <input
              type="checkbox"
              readOnly
              checked={this.state.hideCompleted}
              onClick={this.toggleHideCompleted.bind(this)}
            />
            Hide Completed Tasks
          </label>
          <AccountsUIWrapper />
          { this.props.currentUser ?
            <form className="new-task" onSubmit={this.handleSubmit.bind(this)} >
              <input
                type="text"
                ref="textInput"
                placeholder="Type to add new tasks"
              />
            </form> : ''
          }
        </header>
        <ul>
          {this.renderTasks()}
        </ul>
      </div>
    );
  }
...
cs


리스트에 유저 이름과 작업이 함께 나오도록 수정합니다.


/imports/ui/Task.jsx


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
import React, { Component } from 'react';
import { Tasks } from '../api/tasks.js';
 
// Task component - represents a single todo item
export default class Task extends Component {
    toggleChecked() {
        // Set the checked property to the opposite of its current value
        Tasks.update(this.props.task._id, {
            $set: { checked: !this.props.task.checked },
        });
    }
 
    deleteThisTask() {
        Tasks.remove(this.props.task._id);
    }
 
    render() {
        // Give tasks a different className when they are checked off,
        // so that we can style them nicely in CSS
        const taskClassName = this.props.task.checked ? 'checked' : '';
        return (
            <li className={taskClassName}>
                <button className="delete" onClick={this.deleteThisTask.bind(this)}> &times; </button>
                <input type="checkbox" readOnly checked={!!this.props.task.checked} onClick={this.toggleChecked.bind(this)} />
                <span className="text">
                    <strong>{this.props.task.username}</strong>: {this.props.task.text}
                </span>
            </li>
        );
    }
}
cs


기존에 있던 작업을 지우고 회원가입을 합니다.



이후 새로운 작업을 추가하면 다음과 같이 보입니다.






반응형

+ Recent posts