react中的一些细节知识点:
1、组件中get的使用(作为类的getter)
ES6知识:class类也有自己的getter和setter,写法如下:
Class Component { constructor() { super() this.name = '' } // name的getter get name() { ... } // name的setter set name(value) { ... } }
react组件中的get的使用如下:
/* * renderFullName的getter * 可以直接在render中使用this.renderFullName */ get renderFullName () { return `${this.props.firstName} ${this.props.lastName}`; } render() { return ( <div>{this.renderFullName}</div> ) }
那getter在react组件中有什么用处呢??
constructor (props) { super() this.state = {}; } render () { // 常规写法,在render中直接计算 var fullName = `${this.props.firstName} ${this.props.lastName}`; return ( <div> <h2>{fullName}</h2> </div> ); }
// 较为优雅的写法:,减少render函数的臃肿 renderFullName () { return `${this.props.firstName} ${this.props.lastName}`; } render () { var fullName = this.renderFullName()
<div>{ fullName }</div>
}
// 推荐的做法:通过getter而不是函数形式,减少变量 get renderFullName () { return `${this.props.firstName} ${this.props.lastName}`; } render () { <div>{ this.renderFullName }</div> }
如果你了解Vue的话,那么你知道其中的 computed: {} 计算属性,它的底层也是使用了getter,只不过是对象的getter不是类的getter
// 计算属性,计算renderFullName computed: { renderFullName: () => { return `${this.firstName} ${this.lastName}`; } }
Vue的computed有一个优势就是:
计算属性对比函数执行:会有缓存,减少计算 ---> 计算属性只有在它的相关依赖发生改变时才会重新求值。
这就意味着只要 firstName和lastName还没有发生改变,多次访问renderFullName计算属性会立即返回之前的计算结果,而不必再次执行函数。
那么是否react的getter也有缓存这个优势吗??? 答案是:没有,react中的getter并没有做缓存优化!
2、组件的attr及事件执行顺序:
A、父子组件:以props形式,父传递给子
B、同一组件:后面覆盖前面。
依靠上述规则,那么要使得 attr 的权重最高,应该放到最底层的组件中,而且位置尽量的靠后。
<-- 父组件Parent | 调用子组件并传递onChange属性 --> <div> <Child onChange={this.handleParentChange} /> </div> <-- 子组件Child | 接收父组件onChange, 自己也有onChange属性 --> <input {...this.props} onChange={this.handleChildChange} />
此时,Child组件执行的onChange只是执行handleChildChange事件,handleParentChange事件并不会执行.
- 1.如果只需要执行handleParentChange怎么办?? input中 {...this.props} 与 onChange={this.handleChildChange} 换个位置。
- 2.如果两个事件都需要执行怎么办?? 在Child组件中 handleChildChange 中执行 this.props.handleParentChange
3、类中的方法用ES6形式简写的不同之处: fn = () => {} 与 fn() {} 的区别:
export default Class Child extends Component { constructor (props) { super() this.state = {}; } // 写法1,这是ES6的类的方法写法 fn1() { console.log(this) // 输出 undefined } // 写法2,这是react的方法写法 fn2 = () => { console.log(this) // 输出:Child {props: {…}, context: {…}, refs: {…}, …} } render () { return ( <div> <button onClick={this.fn1}>fn1方法执行</button > <button onClick={this.fn2}>fn2方法执行</button > </div> ); } }
可见两种写法,函数内的this指向时不同的。
那它们就没有相同之处吗??, 以下三种情况是相同的:
情况1:函数内部用不到this的时候,两者相等。
// 写法1,这是ES6的类的方法写法 fn1() { return 1 + 1 } // 写法2,这是react的方法写法 fn2 = () => { return 1 + 1 }
情况2:两者在render中直接执行的时候。
// 写法1,这是ES6的类的方法写法 fn1() { console.log(this) // Child {props: {…}, context: {…}, refs: {…}, …} } // 写法2,这是react的方法写法 fn2 = () => { console.log(this) // 输出:Child {props: {…}, context: {…}, refs: {…}, …} } render () { return ( <div> <button onClick={() => { this.fn1(); }}>fn1方法执行</button > <button onClick={() => { this.fn2(); }}>fn2方法执行</button > </div> ); }
情况3:给this.fn2.bind(this),绑定this作用上下文。
// 写法1,这是ES6的类的方法写法 fn1() { console.log(this) // Child {props: {…}, context: {…}, refs: {…}, …} } // 写法2,这是react的方法写法 fn2 = () => { console.log(this) // 输出:Child {props: {…}, context: {…}, refs: {…}, …} } render () { return ( <div> <button onClick={this.fn1}>fn1方法执行</button > <button onClick={this.fn2.bind(this)}>fn2方法执行</button > </div> ); }
注意,不要和ES6中对象的方法简写弄混了,以下是对象Obeject的方法简写:
阮一峰ES6: http://es6.ruanyifeng.com/#docs/object
4、列表渲染中的数组。
参考:https://doc.react-china.org/docs/lists-and-keys.html
正常的jsx写法是在render中写类似于HTML的语法,标签嵌套标签<div><input /></div>,有js,用 { 花括号 }。
但是不知道你注意过没有,数组可以嵌套在标签内部,正常渲染。
function NumberList(props) { const numbers = [1,2,3,4,5]; // listItems是数组numbers通过map返回的,本质也是个数组。 const listItems = numbers.map((number) => <li>{number}</li> ); return ( <ul> // 可以替换成 [ <li>1</li>, <li>2</li>, .....] {listItems} </ul> ); }
如上所示,标签内部的数组是可以正确渲染的,那么就有以下的写法:
renderItem(name) { const A = <li key={'a'}>A</li>, B = <li key={'b'}>B</li>, C = <li key={'c'}>C</li>, D = <li key={'d'}>D</li>; let operationList; switch (name) { case 1: operationList = [A , B, C] break; case 2: operationList = [B, C, D] break; case 0: operationList = [A] break; } return operationList; } render() { // this.renderItem() 执行结果是数组 return ( <ul>{ this.renderItem() }</ul> ) }