知识点
- React的响应式设计思想和事件绑定
- JSX语法细节补充
- 拆分组件与组件间的传值(父子组件的通信)
- 围绕react衍生出的思考
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
import React, {Component,Fragment} from 'react'; class TodoList extends Component{ render(){ return ( <Fragment> <input/><button>提交</button> <ul> <li>学英语</li> <li>learning react</li> <li></li> </ul> </Fragment> ) } } export default TodoList; |
- 在JSX中,整体(最外层)必须包含在一个大的元素之中
- 如果不要显示最外层的元素,可以使用Fragment
React的响应式设计思想和事件绑定
- react的思想不是基于DOM,而是关注数据层,数据的改变DOM也会改变。
- 一个类有一个构造函数,这个构造函数会最先被执行,构造函数会接受props参数
1 2 3 |
constructor(props){ super(props); } |
- 构造函数中要有super(props),super指的是父类,要调用一次父类的构造函数,这是react中的构造函数必须要有的,是固定的一个写法
- react中定义数据要放在状态state里面,这是一个对象
- 在JSX中使用变量最外层要加大括号,如果要用js表达式也要用{}包裹起来
- react中事件绑定onChange,绑定的时间有一个e参数,这个参数中的e.target是dom,所以可以使用e.target.value来获取输入的value
- 在react中要改变state的值不能直接复制,要使用setState
- 可以使用bind(this)来改变this指向,也可以往里面传递参数
- 在react中使用循环的时候标签中必须有一个key值否则会有警告,这个key值每个必须不同,不推荐使用index 的值
- react中有一个immutable,是指state不允许我们做任何的改变,要改变只能用setState,如果非得要改那么就拷贝一个副本出来再修改,否则react做性能优化的时候就会有问题
// TodoList的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
import React, {Component,Fragment} from 'react'; class TodoList extends Component{ constructor(props){ super(props); this.state = { inputValue: '', list: [] } } render(){ return ( <Fragment> <input value={this.state.inputValue} onChange={this.handleInputChange.bind(this)} /><button onClick={this.handleBtnClick.bind(this)}>提交</button> <ul> { this.state.list.map((item,index)=>{ return <li key={index} onClick={this.handleItemDelete.bind(this,index)} >{item}</li> }) } </ul> </Fragment> ) } handleInputChange(e){ this.setState({ inputValue: e.target.value }); } handleBtnClick(e){ this.setState({ list: [...this.state.list, this.state.inputValue], // 展开运算符 inputValue: '', }) } handleItemDelete(index){ const list = [...this.state.list]; // 拷贝一份 list.splice(index,1); // this.state.list.splice(index,1); // 错误的写法,不能直接修改state this.setState({ list: list }); console.log(index); } } export default TodoList; |
JSX语法细节补充
- 在jsx的代码中编写注释使用,单行注释必须要换行
1 2 3 4 5 |
{/*注释*/} { // 单行注释 } |
- Fragment是一个组件,需要引入
- 标签中不能使用class,要用className来代理,因为all in js的话class是关键字
- 会自动进行html的转义,如果不要转义就可以使用(注意xss)
1 |
dangerouslySetInnerHTML={{__html:item}} |
- 在html中label的作用是扩大点击内容,如果点击了文字光标可以聚焦到input标签
1 2 3 4 5 6 7 |
<label htmlFor="insertArea">输入内容:</label> <input id = "insertArea" className="input" value={this.state.inputValue} onChange={this.handleInputChange.bind(this)} /><button onClick={this.handleBtnClick.bind(this)}>提交</button> |
拆分组件与组件间的传值
- 一半情况下会有一个最顶层的组件,然后每个组件拆分成更多的组件,其他的子组件下面又会有其他的子组件,因此会是一个树形的结构
- 父组件要给子组件传值,直接在标签中赋值或赋一个父组件的方(父组件传递方法的时候this指向要做绑定,.bind(this))法给一个属性,然后子组件通过this.props.xxx拿到父组件传过来的值或者方法
- 有的时候子组件需要调用父组件的方法去改变父组件的数据,父组件传递方法的时候this指向要做绑定,.bind(this)
- 可以利用const做结构复制,注意加{}
- 建议将this指向的操作在构造函数中处理,这样性能好
- 在新版的react中已经不推荐使用this.setState({}),更推荐将这个对象替换成一个函数,函数的话就可以在里面直接对值进行处理了,这个函数可以如果直接返回一个对象,在es6中返回对象可以省略掉return,写成函数的形式这里其实是异步执行得,需要先对值进行保存
- 在setState中可以传递一个参数prevState,这个参数是修改数据之前的数据是什么样的,就等价于this.state,这是一种更好的写法,可以避免不小心改变了state的状态
- es6中如果一个对象是{list:list}那么可以直接写成{list}
将上面TodoList的代码优化、拆分、改写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
import React, {Component,Fragment} from 'react'; import TodoItem from "./TodoItem"; import './style.css' class TodoList extends Component{ constructor(props){ super(props); this.state = { inputValue: '', list: [] }; // 在构造函数中处理this指向性能高 this.handleInputChange = this.handleInputChange.bind(this); this.handleBtnClick = this.handleBtnClick.bind(this); this.handleItemDelete = this.handleItemDelete.bind(this); } render(){ return ( <Fragment> <div> <label htmlFor="insertArea">输入内容:</label> <input id = "insertArea" className="input" value={this.state.inputValue} onChange={this.handleInputChange} /><button onClick={this.handleBtnClick}>提交</button> </div> <ul> {this.getTodoItem()} </ul> </Fragment> ) } getTodoItem(){ return this.state.list.map((item,index)=>{ return ( <TodoItem key = {index} content={item} index={index} deleteItem = {this.handleItemDelete} /> ) }) } handleInputChange(e){ const value = e.target.value; this.setState(() => ({ inputValue: value })) } handleBtnClick(e){ this.setState((prevState)=>({ list: [...prevState.list, prevState.inputValue], // 展开运算符 inputValue: '', })); // 原始的方法 现在已经不推荐使用了 // this.setState({ // list: [...this.state.list, this.state.inputValue], // 展开运算符 // inputValue: '', // }) } handleItemDelete(index){ this.setState((prevState)=>{ const list = [...prevState.list]; list.splice(index,1); return {list} }) // const list = [...this.state.list]; // 拷贝一份 // list.splice(index,1); // // this.state.list.splice(index,1); // 错误的写法,不能直接修改state // this.setState({ // list: list // }); } } export default TodoList; |
拆分开的组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
import React,{Component} from 'react'; class TodoItem extends Component{ constructor(props){ super(props); this.handleClick = this.handleClick.bind(this) // 这样写性能好,也可以在onClick中写 } render(){ const {content} = this.props ; return( <div onClick={this.handleClick}> {content} </div> ) } handleClick(){ const {deleteItem, index} = this.props; deleteItem(index); // this.props.deleteItem(this.props.index) } } export default TodoItem; |
围绕react衍生出的思考
- react是声明式的编程方式(面向数据来编程,自动的根据数据来构建,能节约大量的DOM操作),jquery是命令式的编程方式(里面有百分之60的代码都在做DOM操作)
- react可以与其他框架并存,比如vue和angular,之前的todolist是挂载到了id=root的div的DOM的渲染,不会影响外部,也就是jquery去做其他的部分。
- 组件化,组件一定是大写首字母的,普通的标签是小写首字母
- 单向数据流,父组件可以向子组件传值,但是子组件只能使用这个值,不能去改变这个值!!!(这样是防止多个组件使用同一个数据的时候,其中一个组件如果把父组件数据改变了,导致其他组件出bug,利于代码的维护)
- 视图层框架(不是一个大型的完整框架):真正的项目会有很多的组件,形成组件树,在做大项目的时候光用react是绝对不行的,还要借助其他数据处理工具,因此react将自身定义成一个视图层框架,并不是什么问题都解决,只解决页面和渲染的功能,至于组件之间如何传值是交给其他的数据层框架来做,如flux、redux等来辅助开发
- 函数式编程:最基础的优势是每个函数可以进行拆分,各司其职,另一方面是为了做前端自动化测试的时候如果是函数式的就非常容易测试,只需要输入值看看输出是否正确即可。