【转载】React入门-Todolist制作学习
2016-10-28 18:20
405 查看
我直接看的这个React TodoList的例子(非常好!):
http://www.reqianduan.com/2297.html
文中示例的代码访问路径:http://127.0.0.1:7080/
下面我自己写的部署的服务访问路径:http://127.0.0.1:7060/
服务器的配置使用了Nginx,部署和配置方法,可以参考以前关于Nginx的博客。
先在文中的github页面下载了包
https://github.com/YikaJ/react-todos
解压后,把package.json拷贝到代码目录。
然后运行 npm install 安装依赖库。
安装好之后,把git目录里面的local db目录,放在node_modules目录里面。
需要配置webpack,把webpack.config.js拷贝到目录。
内容如下:
在webstorm里面,可以直接打开一个目录,然后里面的各个文件都能导入。
创建的react目录在: /Users/baidu/Documents/Data/Work/Code/Self/reactjs-todo (另外,上层目录中的reactjs-todo-demo是直接下载的示例程序)
在Webstorm里面打开后(并且按照示例创建了各个文件),列表如下:
其中一些值得注意的地方:
1. 在本机的Nginx上面配置访问。在 /usr/local/etc/nginx/servers (该目录被nginx主配置文件引用)里面创建一个react-todo.conf,内容如下:
然后重启nginx,可以访问。如果有问题,可以查看日志。
/usr/local/var/log/nginx/error.log
2. 主文件是index.html,里面内容如下:
其中,"app" div是会被React进行替换的。
3. webpack配置文件里面包含如下内容:
所以需要先从entry.js开始,内容如下:
scss文件如下 (scss是为了生成css文件,参考webpack里面的配置{ test: /\.scss$/, loader: "style!css!sass"}):
App.js作为entry.js里面引用的文件,内容如下:
注意最后一句,是需要实际进行替换的。
如原文中所说,总的思路是,方法定义在主Component中,然后传递给子Component:
但是例子中的TodoItem的方法都是自行定义处理的,可能因为每个Item都独立吧。
App.js中有几点值得说明:
1. LocalDb是作者自己实现的存储。我看了一下源码,用到了 localStorage[localDb],实际上就是存在了Cookie里面。经过实验,只要删除Cookie,内容就不存在了。
2. “...props”这种语法很好用:
计算需要的数据后,通过props传递到子组件。如果细心的同学应该可以看到像这样的{...props},这就是我之前说过的spread操作符。如果我们没有用这个操作符,就要这样写:
最佳的实践就是,当父组件传props给子组件,然后子组件要将props转发给孙子组件的时候,spread操作符简直让人愉悦!可以对一堆麻烦又丑又长的代码可以say goodbye了!
3. App.js主体的框架是:
TodoHeader, TodoMain, TodoFooter以及TodoItem的各个实现就不具体看了。总结而言:
我们通过父组件来控制状态,并通过props传递,来保证组件内的状态一致。
我们可以非常有效的维护我们的交互代码,因为我们一眼就知道,这个事件属于哪个组件管理。
它的模型其实非常轻,只有View层,但是它带给我们全新的书写前端组件的方法是非常好的,我个人认为如果未来的站点交互性愈来愈多,React是很有可能代替jQuery成为必备的技能。
http://www.reqianduan.com/2297.html
文中示例的代码访问路径:http://127.0.0.1:7080/
下面我自己写的部署的服务访问路径:http://127.0.0.1:7060/
服务器的配置使用了Nginx,部署和配置方法,可以参考以前关于Nginx的博客。
先在文中的github页面下载了包
https://github.com/YikaJ/react-todos
解压后,把package.json拷贝到代码目录。
{ "name": "react-todos", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "ISC", "dependencies": { "react": "^0.13.3", "sass": "^0.5.0" }, "devDependencies": { "babel-core": "^5.5.8", "babel-loader": "^5.1.4", "css-loader": "^0.14.5", "file-loader": "^0.8.4", "jsx-loader": "^0.13.2", "node-libs-browser": "^0.5.2", "node-sass": "^3.2.0", "sass-loader": "^1.0.2", "style-loader": "^0.12.3", "url-loader": "^0.5.6", "webpack": "^1.9.11" } }
然后运行 npm install 安装依赖库。
安装好之后,把git目录里面的local db目录,放在node_modules目录里面。
需要配置webpack,把webpack.config.js拷贝到目录。
内容如下:
'use strict'; var path = require('path'); module.exports = { entry: [ "./src/entry.js" ], output: { path: path.join(__dirname, 'out'), publicPath: './out/', filename: "bundle.js" }, externals: { 'react': 'React' }, module: { loaders: [ { test: /\.js$/, loader: "jsx!babel", include: /src/}, { test: /\.css$/, loader: "style!css"}, { test: /\.scss$/, loader: "style!css!sass"}, { test: /\.svg$/, loader: "url?limit=8192"} ] } };
在webstorm里面,可以直接打开一个目录,然后里面的各个文件都能导入。
创建的react目录在: /Users/baidu/Documents/Data/Work/Code/Self/reactjs-todo (另外,上层目录中的reactjs-todo-demo是直接下载的示例程序)
在Webstorm里面打开后(并且按照示例创建了各个文件),列表如下:
其中一些值得注意的地方:
1. 在本机的Nginx上面配置访问。在 /usr/local/etc/nginx/servers (该目录被nginx主配置文件引用)里面创建一个react-todo.conf,内容如下:
server { listen 7060; server_name localhost; index index.html; root /Users/baidu/Documents/Data/Work/Code/Self/reactjs-todo; }
然后重启nginx,可以访问。如果有问题,可以查看日志。
brew services restart nginx 启动日志位置:
/usr/local/var/log/nginx/error.log
2. 主文件是index.html,里面内容如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>React-Todos</title> <link href="http://cdn.bootcss.com/normalize/3.0.3/normalize.css" rel="stylesheet"> </head> <body> <header> <h1>React-Todos</h1> </header> <div class="container"> <div id="app"></div> </div> <script src="http://cdn.bootcss.com/react/0.13.3/react.min.js"></script> <script src="out/bundle.js"></script> </body> </html>
其中,"app" div是会被React进行替换的。
3. webpack配置文件里面包含如下内容:
entry: [ "./src/entry.js" ],
所以需要先从entry.js开始,内容如下:
/** * Created by baidu on 16/10/29. */ 'use strict'; require('./main.scss'); require('./components/App');
scss文件如下 (scss是为了生成css文件,参考webpack里面的配置{ test: /\.scss$/, loader: "style!css!sass"}):
body{ background: #f5f5f5; } header{ h1{ text-align: center; text-decoration: underline; } } .container{ width: 760px; margin: 0 auto; } .fl{ float: left; } .fr{ float: right; } .clearfix:after{ content: ""; display: table; height: 0; clear: both; } .panel{ background: #fff; border: 1px solid #ddd; padding: 8px; box-shadow: 1px 1px 1px #000; .panel-header{ input{ width: 90%; background: url("./svg/si-glyph-baby.svg") no-repeat; padding: 5px 5px; padding-left: 50px; font-size: 24px; border: none; } border-bottom: 3px solid #ddd; } } .todo-list{ list-style: none; padding: 0; li{ border-bottom: 1px solid #ddd; padding: 10px; font-size: 18px; input[type=checkbox]{ margin-right: 10px; } button{ font-size: 14px; } } } .todo-footer{ margin-left: 10px; input[type=checkbox]{ margin-right: 10px; } }
App.js作为entry.js里面引用的文件,内容如下:
/** * Created by baidu on 16/10/29. */ import React from "react"; import LocalDb from "localDb"; import TodoHeader from "./TodoHeader"; import TodoMain from "./TodoMain"; import TodoFooter from "./TodoFooter"; class App extends React.Component { constructor() { super(); this.db = new LocalDb("React-Todos"); this.state = { todos: this.db.get("todos") || [], isAllChecked: false }; } allChecked() { let isAllChecked = false; if (this.state.todos.every((todo)=> todo.isDone)) { isAllChecked = true; } this.setState({todos: this.state.todos, isAllChecked}); } addTodo(todoItem) { this.state.todos.push(todoItem); this.allChecked(); this.db.set('todos', this.state.todos); } changeTodoState(index, isDone, isChangeAll=false) { if (isChangeAll) { this.setState({ todos: this.state.todos.map( (todo)=>{ todo.isDone = isDone; return todo; } ), isAllChecked: isDone }); } else { this.state.todos[index].isDone = isDone; this.allChecked(); } this.db.set('todos', this.state.todos); } clearDone() { let todos = this.state.todos.filter( (todo)=>!todo.isDone ); this.setState({ todos: todos, isAllChecked: false }); this.db.set('todos', todos); } deleteTodo(index) { this.state.todos.splice(index, 1); this.setState({todos: this.state.todos}); this.db.set('todos', this.state.todos); } render() { var props = { todoCount: this.state.todos.length || 0, todoDoneCount: (this.state.todos && this.state.todos.filter((todo)=>todo.isDone)).length || 0 }; return (<div className = "panel"> <TodoHeader addTodo={this.addTodo.bind(this)}/> <TodoMain deleteTodo={this.deleteTodo.bind(this)} todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)}/> <TodoFooter isAllChecked={this.state.isAllChecked} clearDone={this.clearDone.bind(this)} changeTodoState={this.changeTodoState.bind(this)} {...props}/> </div>) } } React.render(<App/>, document.getElementById("app"));
注意最后一句,是需要实际进行替换的。
如原文中所说,总的思路是,方法定义在主Component中,然后传递给子Component:
React的主流思想就是,所有的state状态和方法都是由父组件控制,然后通过props传递给子组件,形成一个单方向的数据链路,保持各组件的状态一致。
但是例子中的TodoItem的方法都是自行定义处理的,可能因为每个Item都独立吧。
App.js中有几点值得说明:
1. LocalDb是作者自己实现的存储。我看了一下源码,用到了 localStorage[localDb],实际上就是存在了Cookie里面。经过实验,只要删除Cookie,内容就不存在了。
2. “...props”这种语法很好用:
计算需要的数据后,通过props传递到子组件。如果细心的同学应该可以看到像这样的{...props},这就是我之前说过的spread操作符。如果我们没有用这个操作符,就要这样写:
<TodoFooter {...props} /> // spread操作符 <TodoFooter todoCount={props.todoCount} todoDoneCount={props.todoDoneCount} />
最佳的实践就是,当父组件传props给子组件,然后子组件要将props转发给孙子组件的时候,spread操作符简直让人愉悦!可以对一堆麻烦又丑又长的代码可以say goodbye了!
3. App.js主体的框架是:
// 判断是否所有任务的状态都完成,同步底部的全选框 allChecked() // 添加一个任务,参数是一个todoItem的object addTodo(todoItem) // 改变任务的状态,index是第几个,isDone是状态,isChangeAll是控制全部状态的 changeTodoState(index, isDone, isChangeAll=false) // 参数默认位false // 清空已完成 clearDone() // 删除面板上第几个任务 deleteTodo(index) // react用于渲染的函数 render(){ <div className="panel"> <TodoHeader /> <TodoMain /> <TodoFooter /> </div> } 我们可以从render函数看到整个组件的结构,可以看到其实结构非常简单,就是上中下。 上面的TodoHeader自然就是用来输入任务的地方,中间就是展示并操作todo-list的,而底部就是显示数据并提供特殊操作。 这里还是要提醒一句,所有标签都必须闭合,即使是非结对的,也要用斜杠闭合上。 记得,最后要进行React.render的调用。最后我们将整个App渲染到DOM上即可。 React.render(<App/>, document.getElementById("app"));
TodoHeader, TodoMain, TodoFooter以及TodoItem的各个实现就不具体看了。总结而言:
我们通过父组件来控制状态,并通过props传递,来保证组件内的状态一致。
我们可以非常有效的维护我们的交互代码,因为我们一眼就知道,这个事件属于哪个组件管理。
它的模型其实非常轻,只有View层,但是它带给我们全新的书写前端组件的方法是非常好的,我个人认为如果未来的站点交互性愈来愈多,React是很有可能代替jQuery成为必备的技能。
相关文章推荐
- React入门最好的学习实例-TodoList
- react学习之 todolist制作, es6最新写法
- [转载]老篇常谈-Java学习从入门到精通
- 学习Linux网络编程(转载,很不错的入门文章)
- 【转载】黑莓开发学习(入门教程)05-再说开发环境和入门阶段的一些问题
- [转载]20个学习CSS的绝佳网站——让你从入门到精通
- Oracle入门学习心得(转载)
- [转载]Java学习从入门到精通
- 转载 Android入门学习_代码常用布局
- 【转载】黑莓开发学习(入门教程)03-经典的HelloWorld程序
- 【转载】黑莓开发学习(入门教程)02-开发环境搭建
- jquery学习入门到高级(转载博客园)
- 【转载】Java学习从入门到精通
- EXTJS学习系列提高篇:第七篇(转载)作者殷良胜,制作树形菜单之一
- EXTJS学习系列提高篇:第三篇(转载)作者殷良胜,在GridPanel上单击右键显示菜单的制作
- 【转载】黑莓开发学习(入门教程)04-标准界面的HelloWorld程序
- Java学习从入门到精通[转载]
- 动态连接库入门(转载自光头的学习文档http://blog.csdn.net/yuguanglou/archive/2004/11/10/175879.aspx)
- Css 入门学习---css下拉菜单制作
- C#调用存储过程的方法,和简单存储过程创建的方法实例。【转载】为入门的朋友引路,大家互相学习。