React入门实践之Todo List
2016-05-20 13:20
746 查看
上次我们介绍了React入门的Hello World程序,还搭建了一个简单的React运行环境,今天就来写一个TodoList程序,逐步学习React开发。
注意,下面的程序是基于上篇文章中的react-dev项目的,如果没有看过,大家可以移步至:React入门之HelloWorld及环境搭建
根据React的开发思想,一切皆为模块和复合组件,所以我们要做一个TodoList,首先要对这个功能进行分析,划分模块和创建组件,最后才开始实现业务逻辑。
我们的TodoList比较简单,只是列举了几条待办事项的名称和时间,所以我们就来简单划分一下模块吧:
可以看到,TodoList相当于一个容器,里面可以放很多TodoItem组件,接下来,我们先来实现TodoList组件,让它简单地显示一行文字,JSX文件代码如下:
上面的代码先使用React.createClass定义一个TodoList组件,然后在其render方法中定义HTML模板结构,可以看到,我们定义了一个
然后下面的一段代码中我们使用ReactDOM.render来将
当我们运行之后,页面就显示出一行文字,如图:
接下来我们需要创建TodoItem组件了,假设我们有这样一份数据,表示一个todo的列表:
我们希望创建
可以看到,我们在TodoList中添加了两个TodoItem,并且传递了三个属性,这三个属性将
现在再来看看渲染出来的画面吧:
是不是像那么回事了~
但我们并不满足于此,实际生产环境也不会这样使用,我们的数据形式更像下面这样:
我们可以把mockData传递到TodoList中,然后再渲染出TodoItem,再修改一下代码:
上面的代码中我们直接把mockData传递进TodoList组件,然后在TodoList的render方法中要用到map函数对数据进行处理,将其映射为多个TodoItem组件组成的集合。注意map函数中的组件一定要带有一个
实际开发中,我们的数据一开始并不存在,需要在运行过程中通过网络加载,所以我们的程序还不满足实际需要,还要再改进一下代码,最终的文件如下:
这一次我们给TodoList提供了一个url用于通过网络获取真正的数据,在TodoList里面,需要给它一个初始值,这是通过声明
刚学习React的同学们也赶紧跑一下这个小程序吧。
参考:http://facebook.github.io/react/docs/tutorial.html
注意,下面的程序是基于上篇文章中的react-dev项目的,如果没有看过,大家可以移步至:React入门之HelloWorld及环境搭建
根据React的开发思想,一切皆为模块和复合组件,所以我们要做一个TodoList,首先要对这个功能进行分析,划分模块和创建组件,最后才开始实现业务逻辑。
我们的TodoList比较简单,只是列举了几条待办事项的名称和时间,所以我们就来简单划分一下模块吧:
|- TodoList |- TodoItem |- TodoItem
可以看到,TodoList相当于一个容器,里面可以放很多TodoItem组件,接下来,我们先来实现TodoList组件,让它简单地显示一行文字,JSX文件代码如下:
// main.jsx var React = require('react'); var ReactDOM = require('react-dom'); var TodoList = React.createClass({ render: function() { return ( <div className="todoList"> Your todo list goes here. </div> ); } }); ReactDOM.render( <TodoList/>, document.getElementById('container') );
上面的代码先使用React.createClass定义一个TodoList组件,然后在其render方法中定义HTML模板结构,可以看到,我们定义了一个
div标签,内容就显示一行文字,非常的简单。不过需要注意的是,React规定,必须使用
className关键字来定义元素样式的class,一方面
class和浏览器中的保留字冲突,另外这是React经过诸多方面的考量决定的。如果大家想立即探个究竟,具体原因请参考:Why do I have to use className instead of class in React
然后下面的一段代码中我们使用ReactDOM.render来将
<TodoList/>渲染到DOM中去。对应的HTML和CSS如下:
<body> <div id="container"></div> <script type="text/javascript" src="js/main.min.js"></script> </body>
* { margin: 0; padding: 0; box-sizing: border-box; } .todoList { width: 450px; padding: 10px; margin: 10px auto; background-color: wheat; }
当我们运行之后,页面就显示出一行文字,如图:
接下来我们需要创建TodoItem组件了,假设我们有这样一份数据,表示一个todo的列表:
var todo = {id: 0, name: "todo name", time: "8:00"};
我们希望创建
TodoItem组件并将其添加到TodoList中,稍微修改一下代码:
var TodoList = React.createClass({ render: function() { return ( <div className="todoList"> <TodoItem id="0" name="sleep" time="23:00"/> <TodoItem id="1" name="get up" time="8:00"/> </div> ); } }); var TodoItem = React.createClass({ render: function() { return ( <div className="todoItem"> <input type="checkbox" value={this.props.id}/> <div className="name">{this.props.name}</div> <div className="time">{this.props.time}</div> </div> ); } });
可以看到,我们在TodoList中添加了两个TodoItem,并且传递了三个属性,这三个属性将
会在TodoItem中使用props`获取到。下面是TodoItem相关的样式:
.todoItem { width: 400px; height: 40px; background-color: #eee; border-radius: 3px; display: flex; justify-content: center; margin: 10px auto 0; } .todoItem:first-child { margin-top: 0; } .todoItem * { width: 50px; line-height: 40px; text-align: center; } .todoItem input { width: 30px; height: 100%; } .todoItem .name { flex-grow: 1; text-align: left; }
现在再来看看渲染出来的画面吧:
是不是像那么回事了~
但我们并不满足于此,实际生产环境也不会这样使用,我们的数据形式更像下面这样:
var mockData = [ {id: 1, name: "report the updates to Boss", time: "9:30"}, {id: 2, name: "Stand-up meeting", time: "10:00"}, {id: 3, name: "Draw up a plan for next step", time: "11:00"} ];
我们可以把mockData传递到TodoList中,然后再渲染出TodoItem,再修改一下代码:
var TodoList = React.createClass({
render: function() {
//get the data in props, and transform, make them in the form of <TodoItem/>
var todoItems = this.props.data.map(function(todo) {
return (
//the 'key' property is required
<TodoItem key={todo.id} id={todo.id} name={todo.name} time={todo.time}/>
);
});
return (
//we use {todoItems} here instead of <TodoItem/>
<div className="todoList">{todoItems}</div>
);
}
});
var TodoItem = React.createClass({
render: function() {
return (
<div className="todoItem">
<input type="checkbox" value={this.props.id}/>
<div className="name">{this.props.name}</div>
<div className="time">{this.props.time}</div>
</div>
);
}
});
var mockData = [ {id: 1, name: "report the updates to Boss", time: "9:30"}, {id: 2, name: "Stand-up meeting", time: "10:00"}, {id: 3, name: "Draw up a plan for next step", time: "11:00"} ];
ReactDOM.render(
//adding a ‘data’ property referring to mockData
<TodoList data={mockData}/>,
document.getElementById('container')
);
上面的代码中我们直接把mockData传递进TodoList组件,然后在TodoList的render方法中要用到map函数对数据进行处理,将其映射为多个TodoItem组件组成的集合。注意map函数中的组件一定要带有一个
key属性,否则会抛出异常。再来看一下现在的视图吧:
实际开发中,我们的数据一开始并不存在,需要在运行过程中通过网络加载,所以我们的程序还不满足实际需要,还要再改进一下代码,最终的文件如下:
// main.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var TodoList = React.createClass({
getInitialState: function() {
//set the initial state with data
return {data: []};
},
componentDidMount: function() {
console.log('in real dev we get data via:', this.props.url);
//simulate the process of obtaining data
var networkTime = 1000;
var mockData = [ {id: 1, name: "report the updates to Boss", time: "9:30"}, {id: 2, name: "Stand-up meeting", time: "10:00"}, {id: 3, name: "Draw up a plan for next step", time: "11:00"} ];
setTimeout(function() {
//set state to re-render the view
this.setState({data: mockData});
}.bind(this), networkTime);
},
render: function() {
//remember to use 'this.state.data' rather than 'this.props.data'
var todoItems = this.state.data.map(function(todo) {
return (
<TodoItem key={todo.id} id={todo.id} name={todo.name} time={todo.time}/>
);
});
return (
<div className="todoList">{todoItems}</div>
);
}
});
var TodoItem = React.createClass({
render: function() {
return (
<div className="todoItem">
<input type="checkbox" value={this.props.id}/>
<div className="name">{this.props.name}</div>
<div className="time">{this.props.time}</div>
</div>
);
}
});
var url = 'http://localhost:8080/todos';
ReactDOM.render(
//replace the 'data' with 'url'
<TodoList url={url}/>,
document.getElementById('container')
);
这一次我们给TodoList提供了一个url用于通过网络获取真正的数据,在TodoList里面,需要给它一个初始值,这是通过声明
getInitialState函数来实现的,这个函数负责做一些组件初始化的工作,我们初始化data为一个空数组,后面可以通过
state.data来访问,不再通过
props来获取数据了。此外,我们也声明了一个
componentDidMount函数,这个是干嘛的呢,它表示当前组件已被挂载成功,在
render函数执行之后做一些业务逻辑操作,我们就再这个函数里面加载真正需要的数据。注意,此示例中,在获取到数据之后,要记得调用
setState函数将数据替换为最新的集合,这样React会重新渲染视图。
刚学习React的同学们也赶紧跑一下这个小程序吧。
参考:http://facebook.github.io/react/docs/tutorial.html
相关文章推荐
- react 入门 阮一峰
- 【React】《Why did we build React?》 我们为什么要创建React-译文
- 学习iOS、React Native、算法开发的建议
- React Native 中组件的生命周期
- React-native 关于 android真机解决出现连不上服务器
- webpack React+ES6
- Ubuntu React Native 环境搭建
- ReactNative动画(下)
- ReactNative动画(上)
- React
- React从零学起
- ReactNative Android 实现加载本地图片
- 【React教学】输入框自动完成提示——250行实现
- webpack踩坑之路——构建基本的React+ES6项目
- React 设计思想(转)
- 前端路由实现与 react-router 源码分析
- 在window下react-native环境安装
- ReactiveCocoa操作方法(映射,组合)
- react, Stateless Functions, ES6 花括号参数, Spread operator
- 使用Webpack和Babel来搭建React应用程序