本文源代码可以在这里找到

如果你有成为全栈的梦想,METEOR是个不错的平台。


7.在组件状态中存储临时的用户界面数据

在这一章节,我们将在app中添加客户端数据过滤功能,以便用户选择只查看未完成的任务。我们将学习怎样使用React的component state去存储只在客户端用到的临时数据。

首先,我们需要增加一个复选框到App组件:

  1. //imports/ui/App.jsx
  2. <header>
  3. <h1>Todo List</h1>
  4. //新添加内容
  5. <label className="hide-completed">
  6. <input
  7. type="checkbox"
  8. readOnly
  9. checked={this.state.hideCompleted}
  10. onClick={this.toggleHideCompleted.bind(this)}
  11. />
  12. Hide Completed Tasks
  13. </label>
  14. //新添加内容

你可以看到它从this.state.hideCompleted读取数据。React有一个特殊的字段叫state,你可以把组件数据存储和封装在里面。我们需要在组件的构造器中初始化this.state.hideCompleted的值:

  1. //imports/ui/App.jsx
  2. class App extends Component {
  3. //新添加的内容
  4. constructor(props) {
  5. super(props);
  6. this.state = {
  7. hideCompleted: false,
  8. };
  9. }
  10. //新添加的内容
  11. }

我们可以事件管理器中调用this.setState去更新this.state,这将异步更新state属性,并重新渲染组件:

  1. //imports/ui/App.jsx
  2. ReactDOM.findDOMNode(this.refs.textInput).value = '';
  3. }
  4. //新添加的内容
  5. toggleHideCompleted() {
  6. this.setState({
  7. hideCompleted: !this.state.hideCompleted,
  8. });
  9. }
  10. //新添加的内容
  11. }

this.state.hideCompleted为true时,我们需要更新renderTasks方法去过滤已经完成的任务:

  1. //imports/ui/App.jsx
  2. renderTasks() {
  3. let filteredTasks = this.props.tasks;
  4. if (this.state.hideCompleted) {
  5. filteredTasks = filteredTasks.filter(task => !task.checked);
  6. }
  7. return filteredTasks.map((task) => (
  8. <Task key={task._id} task={task} />
  9. ));
  10. }

如果你现在选择复选框,任务列表不会再展现已经完成的任务了。

新的特性:显示未完成任务的数目

现在我们要写一个查询条件,用来过滤掉已经完成的任务。我们也可以用相同的查询来显示已完成的任务总数。为此,我们需要在我们的数据容器中拿到一个计数,并在render方法中添加一行代码。因为我们已经有客户端集合中的数据,增加这个额外的计数不需要向服务端发起任何请求。

  1. //imports/ui/App.jsx
  2. export default createContainer(() => {
  3. return {
  4. tasks: Tasks.find({}, { sort: { createdAt: -1 } }).fetch(),
  5. //新添加的的内容
  6. incompleteCount: Tasks.find({ checked: { $ne: true } }).count(),
  7. //新添加的的内容
  8. };
  9. }, App);
  1. //imports/ui/App.jsx
  2. return (
  3. <div className="container">
  4. <header>
  5. //新添加的的内容
  6. <h1>Todo List ({this.props.incompleteCount})</h1>
  7. //新添加的的内容
  8. <label className="hide-completed">
  9. <input
  10. //...省略一些代码...
  11. App.propTypes = {
  12. tasks: PropTypes.array.isRequired,
  13. //新添加的的内容
  14. incompleteCount: PropTypes.number.isRequired,
  15. //新添加的的内容
  16. };
  17. )

上一节:Running on mobile(在移动端运行)

下一节:Adding user accounts(添加用户账号)待翻译