TodoList 接收父组件 TodoApp 中的数组,并将其渲染成一个 ul 列表:
import React, { Component } from 'react'; import TodoItem from './TodoItem'; class TodoList extends Component { render() { return ( <ul className="list"> { this.props.items.map((item)=>{ return ( <TodoItem key={item.id} taskid={item.id} status = {item.status} text={item.text} handleComplete={this.props.handleComplete} handleDelete={this.props.handleDelete} /> ) }) } </ul> ); } } export default TodoList; 3.4 TodoItem.js在 TodoList 遍历数组时,把每一项元素交给 TodoItem 组件,它会渲染成一个 li 元素:
import React, { Component } from 'react'; class TodoItem extends Component { constructor(props) { super(props); this.taskComplete = this.taskComplete.bind(this); this.taskDelete = this.taskDelete.bind(this); } render() { let isCompleted = this.props.status === 1; return ( <li className={isCompleted?'complete':''}> <input type="checkbox" checked={isCompleted} onChange={this.taskComplete}/> <span>{this.props.text}</span> <button className="btn-del" onClick={this.taskDelete}>删除</button> </li> ); } taskComplete() { this.props.handleComplete(this.props.taskid); } taskDelete() { this.props.handleDelete(this.props.taskid); } shouldComponentUpdate(nextProps, nextState) { if (nextProps.text !== this.props.text || nextProps.status !== this.props.status) { return true; } else { return false; } } } export default TodoItem;这几个文件写完之后,进入 react-todoapp 目录,cmd 运行 npm start,访问 :3000 就能查看最终的结果了。
4. 思考 4.1 JSXTodoApp 组件在 render 方法渲染时,使用了一个既不是字符串也不是 HTML 的语法,它被称为 JSX,是 JavaScript 的语法扩展,使用它可以很方便的创建 DOM。
JSX 看起来像是模板语言,但它具有 JavaScript 的全部功能:
遇到 <> 就当作 HTML 解析
遇到 {} 就当作 JavaScript 解析
4.2 组件通信这里主要有两种通信情况:
父组件向子组件通信
子组件向父组件通信
每个组件都有一个 props 对象,用以访问组件的属性,所以,父组件可以向子组件传递一组 props 供其使用,就像方法传参一样。
子组件向父组件通信,可以利用回调函数:父组件将一个函数作为 props 传递给子组件,子组件调用该回调函数,便可向父组件通信。
回调函数也是增删一组数据,那么为什么不直接把数据传给子组件,直接操作?这是因为 props 是只读的,不能修改,改了就会报错:
TypeError: Cannot assign to read only property 'items' of object '#<Object>'这样设计是为了保证相同的输入,每次都输出相同的结果。
4.3 组件状态组件分有状态和无状态,比如 TodoApp 是有状态的,TodoList 和 TodoItem 是无状态的。这个状态 state 和 props 类似,也是一组数据,但它是组件内部私有的,其他组件访问不了。
所以,TodoApp 组件只有在自己内部才可以对 this.state.items 内部增删改,就算把它传给其他组件,也是只读的。
在更新 state 时需要注意:
不能直接修改 state:统一使用 setState() 更新
setState 是一个异步方法,可传递一个函数在执行结束后回调,setState({},()=>{..})
setState 会合并更新,就是可以只传递变更的部分
组件的 state 可以随着用户交互而产生变化,但 props 一旦定义就不再发生改变。
4.4 单向数据流子组件不能直接修改父组件的数据,数据只能由父组件传给子组件,更新只能通过回调,这个特性被称作单向数据流。
它保证了组件相同的输入,每次都是相同的输出。所有数据都在父组件,代码易于理解,方便维护。
4.5 其他import React, { Component } from 'react'; 这是 ES6 解构赋值 的用法,解构赋值是对赋值运算符的扩展,可以将属性/值从对象/数组中取出,赋值给其他变量。
这个导入就相当于:
import React from 'react'; const Component = React.Component;类比 Java 的话,可以这样理解,React 相当于包,Component 相当于包下的类,要使用都要先导入。
5. 总结简单写了下自己的理解,仅供参考!还是要看官方文档:
中文:https://react.docschina.org/docs/getting-started.html
英文:https://reactjs.org/docs/getting-started.html
此次编写的 react-todoapp 源码地址:https://github.com/chuondev/react-todoapp