【转载】React入门-Todolist制作学习
我直接看的这个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拷贝到代码目录。
{
"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 入门实例教程(转载)
本人转载自: React 入门实例教程
- React 入门实例教程(转载)
现在最热门的前端框架,毫无疑问是 React . 上周,基于 React 的 React Native 发布,结果一天之内,就获得了 5000 颗星,受瞩目程度可见一斑. React 起源于 Face ...
- React入门——制作一个TodoList App
源码 import React, { Component, Fragment } from "react"; class TodoList extends Component { ...
- React 入门-写个 TodoList 实例
React 是一个用于构建用户界面的 JavaScript 库,主要特点有: 声明式渲染:设计好数据和视图的关系,数据变化 React 自动渲染,不必亲自操作DOM 组件化:页面切分成多个小部件,通过 ...
- React-TodoList
React入门最好的学习实例-TodoList 前言 React 的核心思想是:封装组件,各个组件维护自己的状态和 UI,当状态变更,自动重新渲染整个组件. 最近前端界闹的沸沸扬扬的技术当属react ...
- react入门学习及总结
前言 不知不觉一年又过去了,新的一年又到来,2019应该要好好思考,好好学点有用的东西,规划下自己今后的学习方向,不要再像以前那样感觉很迷茫. react简单介绍 官网及中文文档 https://re ...
- React 入门学习笔记整理目录
React 入门学习笔记整理(一)--搭建环境 React 入门学习笔记整理(二)-- JSX简介与语法 React 入门学习笔记整理(三)-- 组件 React 入门学习笔记整理(四)-- 事件 R ...
- React 入门学习笔记2
摘自阮一峰:React入门实例教程,转载请注明出处. 一.获取真实的DOM节点 组件并不是真实的 DOM 节点,而是存在于内存之中的一种数据结构,叫做虚拟 DOM (virtual DOM).只有当它 ...
- React 入门学习笔记1
摘自阮一峰:React入门实例教程,转载请注明出处. 一. 使用React的html模板 使用React, 我们需要加载3个库,react.js, react-dom.js, 和browser.js. ...
随机推荐
- Video Toolbox:读写解码回调函数CVImageBufferRef的YUV图像
本文档基于H.264的解码,介绍读写Video Toolbox解码回调函数参数CVImageBufferRef中的YUV或RGB数据的方法,并给出CVImageBufferRef生成灰度图代码.方便调 ...
- iOS10.0 TabBar Bug(底部同时展示原生和自定义tabBar)-b
在没有发布iOS10的时候,在任何模拟器测试下效果正常,更新iOS10后,测试出现BUG先放一张bug之前的效果图: 修改前出现的bug 在检查了所有问题之后,最后把问题定位在了原生系统tabBar底 ...
- Codeforces Round #348 (VK Cup 2016 Round 2, Div. 2 Edition) D. Little Artem and Dance
题目链接: http://codeforces.com/contest/669/problem/D 题意: 给你一个初始序列:1,2,3,...,n. 现在有两种操作: 1.循环左移,循环右移. 2. ...
- [CFgym]2015-2016 ACM-ICPC Pacific Northwest Regional Contest小结
*感谢两位浙江大佬带我飞 贴下成绩 div2 div1 *div2不是我打的上个厕所就5/11了 比赛小结 A [题目大意] 有n(n<=500)个机场,两两之间距离是g[i][j],每经停一个 ...
- [设计模式] 23 访问者模式 visitor Pattern
在GOF的<设计模式:可复用面向对象软件的基础>一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作.它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作.访问 ...
- java给图片加水印代码
try { String targetImg = "D:/Blue hills.jpg"; // String pressImg = "D:/20130311220300 ...
- 【设计模式六大原则3】依赖倒置原则(Dependence Inversion Principle)
定义:高层模块不应该依赖低层模块,二者都应该依赖其抽象:抽象不应该依赖细节:细节应该依赖抽象. 问题由来:类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成.这种场景下,类 ...
- hdu 1753 大明A+B
题目:http://acm.hdu.edu.cn/showproblem.php?pid=1753 容易出错的事例: 0.1 0.2 1.88 22.22 1 0.01 大概出错的几个点,做久了思维根 ...
- 如何正确学习JavaScript
不要这样学习JavaScript 不要一开始就埋头在成堆的JavaScript在线教程里 ,这是最糟糕的学习方法.或许在看过无数个教程后会有点成效,但这样不分层次结构地学习一个东西实在是十分低效,在实 ...
- 李洪强iOS开发之OC语言@property @synthesize和id
OC语言@property @synthesize和id 一.@property @synthesize关键字 注意:这两个关键字是编译器特性,让xcode可以自动生成getter和setter的声明 ...