首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >待办事项清单

待办事项清单
EN

Code Review用户
提问于 2016-01-08 01:43:05
回答 2查看 2.1K关注 0票数 7

我已经写了一个反应清单应用程序,因为我是一个初学者,这是我的第一个应用,我觉得它可以改进。如果能提供一些帮助来改进它,以及如何或为什么改进得更好,我们将不胜感激。

这是它的一个工作演示

代码语言:javascript
复制
var ToDoContainer = React.createClass({
    getInitialState: function(){
        var tasks = [
                {task:"Go to the gym", completed:false, id:1 }, 
                {task:"Do yoga", completed:false, id:2 },
                {task:"Buy groceries", completed:true, id:3 },
                {task:"Get tire fixed", completed:true, id:4}
        ];

        return {
            tasks:tasks,
            numCompleted:null
        }
    },
    addTask: function(task){
        this.setState({
            tasks:this.state.tasks.concat(task) 
        }); 
    },
    clearComplete: function(){

        var remainingTasks = this.state.tasks.filter(function(task){
            if (!task.completed) return task;
        });

        this.setState({
            tasks:remainingTasks
        });

    },
    markComplete: function(e){
        console.log('markComplete')
        var id = e.target.getAttribute('data-id');
        var tempTasks = this.state.tasks;

        tempTasks.forEach(function(task){
            if (id == task.id) {
                if (task.completed){
                    task.completed = false; 
                }
                else if (!task.completed) {
                    task.completed = true;  
                }
            }
        })

        this.setState({
            tasks:tempTasks
        });
    },
    render: function(){
        var numCompleted = this.state.tasks.filter(function(task){
            return task.completed;
        }).length

        var numRemaining = this.state.tasks.filter(function(task){
            return !task.completed;
        }).length

        return (
            <div className="rowFluid">
                <div className="well row col-md-4 col-md-offset-4">
                    <h3 className="text-left">You have {numRemaining} tasks to do:</h3>
                    <TaskList tasks={this.state.tasks} check={this.markComplete} />
                    <AddTask addNew={this.addTask} />
                    <ClearTask clear={this.clearComplete} numCompleted={numCompleted}/>
                </div>
            </div>
        )
    }
});

var TaskList = React.createClass({
    handleCheck: function(e){
        console.log('handleCheck')
        this.props.check(e);
    },
    getInitialState: function(){
        return {
            data:this.props.tasks
        }
    },
    render: function(){
        var that = this;

        var task = this.props.tasks.map(function(task, index){
                return <li key={index} className={task.completed ? "complete" : "incomplete"} >
                            <input type="checkbox" checked={task.completed} onChange={that.handleCheck} data-id={task.id}/>
                            {task.task}
                        </li>
        });

        return (
            <div>
                <ul className="list-unstyled">
                    {task}
                </ul>
            </div>
        )
    }
});

var AddTask = React.createClass({
    getInitialState: function(){
        return{
            newTask:""
        }
    },
    handleChange: function(e){
        this.setState({
            newTask:e.target.value
        });
    },
    handleSubmit: function(e){
        e.preventDefault();

        this.props.addNew({task:this.state.newTask, completed:false, id:Date.now()});
        this.setState({
            newTask:""
        });
    },
    render: function(){
        var inputStyle = {
            marginRight: "10px"
        }

        return (    
            <div className="text-left">
                <form onSubmit={this.handleSubmit}>
                    <input type="text" value={this.state.newTask} onChange={this.handleChange} style={inputStyle}/>
                    <input type="submit" value="Add Task" disabled={this.state.newTask == ""} />
                </form>
            </div>

        )
    }
});

var ClearTask = React.createClass({

    clear: function(){
        this.props.clear();
    },
    render: function(){
        var buttonStyle = {
            marginTop: "10px"
        }

        return (
            <button onClick={this.clear} value="Clear Completed" clear={this.clearComplete} disabled={this.props.numCompleted==0} className="text-center" style={buttonStyle}>Clear Completed</button>
        )   
    }
})


ReactDOM.render(<ToDoContainer />, document.getElementById('app'));
EN

回答 2

Code Review用户

回答已采纳

发布于 2016-01-08 03:54:37

代码语言:javascript
复制
return {
    tasks:tasks,
    numCompleted:null
}

numCompleted在任何地方都没有被使用。从数据中删除if。而且,它是一个“计算属性”,可以从tasks中计算。我注意到你在渲染时计算它。考虑把它放在一个函数中。

代码语言:javascript
复制
getCompletedTaskCount: function(){
  return this.state.tasks.filter(task => task.completed).length;
},
getNotCompletedTaskCount: function(){
  return this.state.tasks.filter(task => !task.completed).length;
},
clearComplete: function(){
    this.setState({
        tasks: this.state.tasks.filter(task => !task.completed);
    });
},

由于您使用的是React,我假设您使用的是Babel,因此我们可以访问ES6传输溢出。ES6提供了新的语法来简化代码。在上面的示例中,我使用箭头函数及其隐式返回表达式值的能力。

此外,我注意到您计算渲染上的完整和不完整的任务。我建议您将这些逻辑转换为函数,以便可以重用它们。它还使它们可见,并且减少了render函数中的杂乱。

代码语言:javascript
复制
markComplete: function(e){
    console.log('markComplete')
    var id = e.target.getAttribute('data-id');
    var tempTasks = this.state.tasks;

    tempTasks.forEach(function(task){
        if (id == task.id) {
            if (task.completed){
                task.completed = false; 
            }
            else if (!task.completed) {
                task.completed = true;  
            }
        }
    })

    this.setState({
        tasks:tempTasks
    });
},

我建议反对console.log进行调试。您最不想养成的习惯是在代码中忘记console调用。我建议您在dev工具中学习使用断点。功能更强大,不会在代码中留下垃圾。

markComplete是误导性的。这不仅仅是标记任务的完成。它在切换整个状态。您应该适当地命名它,比如toggleCompleteness

代码语言:javascript
复制
return <li key={index} className={task.completed ? "complete" : "incomplete"} >

这里的问题是您的CSS类。completeincomplete是非常通用的。它可能会被应用程序中使用相同名称的其他库杀死。有了这一点,您就会开始考虑名称空间,您的CSS最终会变成这样:

代码语言:javascript
复制
.todo-list .task .complete{...}

其效果是这种样式具有0-3-0的特殊性(0 ids、3类、0元素)。要重写它,您需要1-x-x ( id)或0-4-0 (4个类)或0-3-0 (3个类,但在后面定义)。随着应用程序变得越来越大,这会使你的CSS生活成为一场覆盖的战斗。

为了解决这个问题,我建议你阅读关于BEM的文章。在要点中,它是CSS类的命名约定,允许您构建低特异性、精确目标的选择器,这些选择器很容易识别。如果您可以安全地说这种样式只会影响这个组件而不影响其他任何东西,那么甚至不需要覆盖。

代码语言:javascript
复制
this.props.addNew({task:this.state.newTask, completed:false, id:Date.now()});

completedid应该由最顶层的组件中的addTask来填充,而addNew只应该用newTask来调用。这是为了将数据结构的知识隔离到代码中的一个位置。

相关的场景是当您的数据结构发生变化时。如果你这样写的话,你就会在寻找硬编码的数据结构。然而,如果您只是将其隔离在一个地方,则只会更改代码的这一部分。

另外,不要使用Date.now()作为ID,而是生成GUID。以下是JS中一个方便的实现。如果您正在寻找一种快速识别事物的方法,我个人使用('' + Math.random()).slice(2)作为一个快速ID解决方案,因为如果您快速地连续运行它(如in循环),Date.now()可以产生相同的值。

代码语言:javascript
复制
<div className="text-left">
    <form onSubmit={this.handleSubmit}>
        <input type="text" value={this.state.newTask} onChange={this.handleChange} style={inputStyle}/>
        <input type="submit" value="Add Task" disabled={this.state.newTask == ""} />
    </form>
</div>

在这里,<form>是过火的,因为除了与onSubmit事件挂钩之外,您的处理程序不使用任何有关表单的内容。您可以删除<form>,用<button>替换输入按钮输入,并在其上放置一个调用handleSubmitonClick

代码语言:javascript
复制
var buttonStyle = {
    marginTop: "10px"
}

使用BEM约定的另一个原因是内联样式的特异性要高于is,而重写它们的唯一方法是替换内联样式或在样式表中使用!important。再说一次,你不希望你的CSS成为一场压倒一切的战斗。

票数 6
EN

Code Review用户

发布于 2016-01-08 02:03:49

我现在不能为你提供一个完整的评论,但以下是一些小问题:

一对简化的

ToDoContainer.render中,这是:

代码语言:javascript
复制
var numCompleted = this.state.tasks.filter(function(task){
    return task.completed;
}).length

var numRemaining = this.state.tasks.filter(function(task){
    return !task.completed;
}).length

就是做额外的工作。numRemaining只是this.state.tasks.length - numCompleted,不需要做第二个filter

此外,在ToDoContainer.clearComplete中,如下所示:

代码语言:javascript
复制
var remainingTasks = this.state.tasks.filter(function(task){
    if (!task.completed) return task;
});

可以稍微简化成

代码语言:javascript
复制
var remainingTasks = this.state.tasks.filter(function(task) {
    return !task.completed;
});

因为filter只关心函数的真/假结果。

切换布尔

ToDoContainer.markComplete中,这是:

代码语言:javascript
复制
if (task.completed){
    task.completed = false; 
}
else if (!task.completed) {
    task.completed = true;  
}

可以简化为

代码语言:javascript
复制
task.completed = !task.completed;

这是一个常用的用来转换布尔值的成语。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/116181

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档