Code Review Stack Exchange is a question and answer site for peer programmer code reviews. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I have a working useless todo app created with ReactJS. I'm just wondering if my code can be improved.

This app can add a todo item and it can display editable list of todo items.

This is my ReactJS code.

var TodoApp = React.createClass({
    getInitialState: function() {
        return {items: []};
    },
    addItem: function(item) {
        var allItems = this.state.items.concat([item]);
        this.updateItems(allItems);
    },
    editItem: function(editedItem) {
        var allItems = this.state.items.map(function(item) {
            if (item.id !== editedItem.id) {
                return item;
            }

            return editedItem;
        });

        this.updateItems(allItems);
    },
    updateItems: function(items) {
        this.setState({items: items});
    },
    render: function() {
        return (
            <div className="todo-app">
                <TodoForm onFormSubmit={this.addItem}/>
                <TodoList items={this.state.items} onItemEdit={this.editItem}/>
            </div>
        );
    }
});

var TodoForm = React.createClass({
    getInitialState: function() {
        return {item: {id: 0, title: '', description: ''}};
    },
    render: function() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input type="hidden" ref="id" value={this.state.item.id} onChange={this.handleUserInput}/>
                <input type="text" ref="title" value={this.state.item.title} onChange={this.handleUserInput}/>
                <input type="text" ref="description" value={this.state.item.description} onChange={this.handleUserInput}/>
                <input type="submit" value="Add"/>
            </form>
        );
    },
    handleSubmit: function(e) {
        e.preventDefault();

        this.props.onFormSubmit(this.state.item);
        this.setState({item: {id: 0, title: '', description: '', done: false}});
    },
    handleUserInput: function() {
        this.setState({item: {
            id: this.refs.id.value,
            title: this.refs.title.value,
            description: this.refs.description.value,
            done: false
        }});
    }
});

var TodoList = React.createClass({
    render: function() {
        var component = this;

        var itemNodes = this.props.items.map(function(item) {
            return <TodoListItem key={item.title} item={item} onFormSubmit={component.props.onItemEdit}/>
        });

        return (
            <ul>{itemNodes}</ul>
        );
    }
});

var TodoListItem = React.createClass({
    getInitialState: function() {
        return {
            id: this.props.item.id,
            done: this.props.item.done,
            title: this.props.item.title,
            description: this.props.item.description,
        };
    },
    render: function() {
        return (
            <li>
                <form onSubmit={this.handleFormSubmit}>
                    <input type="hidden" ref="id" value={this.state.id}/>
                    <input type="checkbox" ref="done" value={this.state.done} onChange={this.handleUserInput}/>
                    <input type="text" ref="title" value={this.state.title} onChange={this.handleUserInput}/>
                    <input type="text" ref="description" value={this.state.description} onChange={this.handleUserInput}/>
                    <input type="submit" value="Save"/>
                </form>
            </li>
        );
    },
    handleUserInput: function() {
        this.setState({
            id: this.refs.id.value,
            done: this.refs.done.checked,
            title: this.refs.title.value,
            description: this.refs.description.value
        });
    },
    handleFormSubmit: function(e) {
        e.preventDefault();
        this.props.onFormSubmit(this.state);
    }
});

ReactDOM.render(<TodoApp/>, document.getElementById('todoListBox'));

ReactJS said in their docs that components should be stateless as possible. I'm aware that in the TodoListItem component, It has a state based from its props. I did that so I can change the form inside TodoListItem.

Is there any other possible solutions to do this other than their two way binding add-on?

share|improve this question
up vote 0 down vote accepted

So I managed to eliminate the TodoListItem's state, which is based on its props, by reusing the TodoForm component with a minor tweak for an inline form.

This is the TodoListItem and TodoForm component now.

var TodoForm = React.createClass({
    getInitialState: function() {
        return {item: {
            id: this.props.todoId,
            title: this.props.todoTitle,
            description: this.props.todoDescription,
            done: this.props.todoDone
        },
        isAnInlineForm: this.props.isAnInlineForm};
    },
    render: function() {
        return (
            <form onSubmit={this.handleSubmit}>
                <input type="checkbox" ref="done" checked={this.state.item.done} onChange={this.handleUserInput}/>
                <input type="hidden" ref="id" value={this.state.item.id} onChange={this.handleUserInput}/>
                <input type="text" ref="title" value={this.state.item.title} onChange={this.handleUserInput}/>
                <input type="text" ref="description" value={this.state.item.description} onChange={this.handleUserInput}/>
                <input type="submit" value="Save"/>
            </form>
        );
    },
    handleSubmit: function(e) {
        e.preventDefault();

        this.props.onFormSubmit(this.state.item);

        if (!this.state.isAnInlineForm) {
            this.setState({item: {id: 0, title: '', description: '', done: false}});
        }
    },
    handleUserInput: function() {
        this.setState({item: {
            id: this.refs.id.value,
            title: this.refs.title.value,
            description: this.refs.description.value,
            done: this.refs.done.checked
        }});
    }
});


var TodoListItem = React.createClass({
    render: function() {
        return (
            <li>
                <TodoForm onFormSubmit={this.handleFormSubmit}
                          todoId={this.props.item.id}
                          todoDone={this.props.item.done}
                          todoTitle={this.props.item.title}
                          todoDescription={this.props.item.description}
                          isAnInlineForm={true}
                    />
            </li>
        );
    },
    handleFormSubmit: function(item) {
        this.props.onFormSubmit(item);
    }
});
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.