25 | this.input = node}
30 | onKeyDown={this.addTodo.bind(this)}
31 | />
32 |
33 | )
34 | }
35 | };
36 |
37 | export default TodoHeader;
--------------------------------------------------------------------------------
/src/components/TodoFooter.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { NavLink } from 'react-router-dom';
3 |
4 | const TodoFooter = ({ remainingCount, hasCompleted, onClearCompletedClick }) => {
5 | let clearCompletedButton;
6 |
7 | if (hasCompleted) {
8 | clearCompletedButton = (
9 |
15 | );
16 | }
17 |
18 | return (
19 |
28 | );
29 | };
30 |
31 | export default TodoFooter;
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 RxJS 中文社区
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | # React RxJS Todos
6 |
7 | This repo shows a basic todos example base on the famous [TodoMVC](https://github.com/tastejs/todomvc) but using RxJS and React. The goal is to show how to use the Observables data architecture pattern within React. The implementation was inspired by the [React Rx TodoMVC Example](https://github.com/fdecampredon/react-rxjs-todomvc).
8 |
9 | > Try the [live demo](https://rxjs-cn.github.io/react-rxjs-todos/) here.
10 |
11 | ## Install
12 |
13 | > This React app was build with [create-react-app](https://github.com/facebookincubator/create-react-app).
14 |
15 | ```shell
16 | # clone the repo
17 | git clone git@github.com:RxJS-CN/react-rxjs-todos.git
18 |
19 | # change into the repo directory
20 | cd react-rxjs-todos
21 |
22 | # install dependencies
23 | npm install
24 |
25 | # run
26 | npm start
27 | ```
28 |
29 | Then visit [http://localhost:3000](http://localhost:3000) in your browser.
30 |
31 | ## Angular Version
32 |
33 | If you prefer Angular, you can checkout out [Angular RxJS Todos](https://github.com/RxJS-CN/angular-rxjs-todos)
34 |
35 | ## License
36 |
37 | MIT
38 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
11 |
12 |
13 |
22 | React RxJS Todos
23 |
24 |
25 |
28 |
29 |
33 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/src/components/TodoItem.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import classnames from 'classnames';
3 |
4 | const ENTER_KEY = 13;
5 | const ESCAPE_KEY = 27;
6 |
7 | class TodoItem extends Component {
8 |
9 | state = {
10 | editing: false,
11 | editTitle: this.props.todo.title
12 | }
13 |
14 | handleChange(event) {
15 | this.setState({ editTitle: event.target.value });
16 | }
17 |
18 | handleEdit() {
19 | this.setState({ editing: true });
20 | }
21 |
22 | handleKeyDown({ keyCode }) {
23 | if (keyCode === ESCAPE_KEY) {
24 | this.handleStop();
25 | } else if (keyCode === ENTER_KEY) {
26 | this.handleStop();
27 | }
28 | }
29 |
30 | handleStop() {
31 | this.setState({ editing: false });
32 | this.handleSubmit();
33 | }
34 |
35 | handleSubmit() {
36 | if (this.state.editTitle.trim().length) {
37 | this.props.onUpdate(this.props.todo.id, this.state.editTitle);
38 | } else {
39 | this.props.onRemoveClick(this.props.todo.id);
40 | }
41 | }
42 |
43 | render() {
44 | const {
45 | todo,
46 | onRemoveClick,
47 | onToggleClick,
48 | } = this.props;
49 | const { editing } = this.state;
50 | const liClass = classnames({
51 | completed: todo.completed,
52 | editing : editing
53 | });
54 |
55 | return (
56 |