import React from 'react'; function A() { return ( <h1>鱼鱼dev</h1> ) }
在这里咱们并无使用到React变量,那为何还要引用React进来呢?javascript
能够试一下,若是咱们省略了React的引入操做import React from 'react';
,就会报如下的错误:java
咱们通过babel转化后,会将上述代码转换成:react
function A() { return React.createElement("h1", null, "鱼鱼dev"); }
因此能够看出来,JSX只是React.createElement(component, props, ...children)
的语法糖。es6
React一开始的理念是想与浏览器的DOM API保持一致,而不是与HTML保持一致。因此更愿意选择DOM API中的className属性。浏览器
这里提一句,驼峰命名分为大驼峰和小驼峰,大驼峰为首字母为大写,其他每一个单词首字母大写。小驼峰为首字母小写,其他每一个单词首字母小写。还有另外两种主流的命名规则,一是下划线链接符,一是横杠链接符。
同上,React的理念是与浏览器的DOM API保持一致,也就使用了DOM API中的小驼峰命名的风格。babel
这里有两个问题dom
super
?props
?super
? 其实这不是React的限制,而是JavaScript的限制。要想在构造函数里调用this
,必须得在此以前调用过super。这里的缘由涉及到了JavaScript的”继承“。函数
如若没有调用super:性能
JavaScript是经过原型链来实现继承的,在此咱们不深究原型链,单说在原型链中super的意义。super指代着父类的构造函数,在子类的构造函数中调用super()
,则意味着调用了父类的构造函数,从而使得建立子类的实例时,不光有子类的属性,还会有父类的属性。this
因此说,如过说在子类的构造函数中没有调用super
的话,则子类的实例中不会有父类的属性值。这就使得这个继承名存实亡了。因此JavaScript规定继承时,必须得在子类的构造函数中调用super
。
props
你必须得在super调用时传入props
才能在构造函数中使用this.props
,不然使用this.props
会报undefined没有这个属性。不过在构造函数以后,如render函数中却能在其中使用this.props
。
为何呢?
这是由于在React的构造函数被调用以后,会给建立的React实例对象绑入一个props
属性,其值就是props
。
const instance = new YourComponent(props); instance.props = props
不过因为是在构造函数被调用后,才绑如props属性,也就是说在构造函数执行时,this
是没有props
这个尚需经的。
因此说,仍是得在super中传入props,不然就没法在构造函数中使用this.props
。
class App extends React.Component { constructor (props) { super(props);// 既调用了super,又传入了props console.log(this.props);// 能够访问到值,而且不会报错 } render () { console.log(this.props);// 能够访问到值 return <h1>鱼鱼dev</h1> } }
class App extends React.Component { constructor (props) { super();// 调用了super,不传入props console.log(this.props);// undefined } render () { console.log(this.props);// 能够访问到值 return <h1>鱼鱼dev</h1> } }
class App extends React.Component { constructor (props) { // 既不调用super,也不传入props console.log(this.props);// 这里就直接报错了 } render () { console.log(this.props); return <h1>鱼鱼dev</h1> } }
得益于React中的babel的强大,babel提供了es6中都不支持的实例属性的写法,也就是说实例属性你不光能够在构造函数中声明,还能够像这样写:
class A { a = '1' }
而若是用这种写法,也就不用在类中写构造函数了。因此继承也不用手动调用super来继承父类的实例属性,默认就帮你调用好了。
class A { a = '1' } class B extends A { b = '2' } console.log(new B().a);// '1'
因此React中能够这样写:
class App extends React.Component { render () { console.log(this.props);// 有值 return <h1>鱼鱼dev</h1> } }
前面有提到,JSX是React.createComponent(component, props, ...children)
的语法糖,在这里component
的类型能够是string或ReactClasstype。
这是在React.createComponent(component, props, ...children)
,而在JSX中是如何区别是string仍是ReactComponent呢?若是是大写开头,是ReactComponent,若是是小写开头,是string。
function A() { // 小写开头,React认为它是原生dom节点。babel后 // 为React.createComponent("div",null); return <div></div> }
import MyComponent from './myComponent.js'; function A() { // 大写开头,React认为他是自定义组件。babel后 // 为React.createComponent(MyComponent,null); return <MyComponent></MyComponent> }
import myComponent from './myComponent.js';// 这里有个改动,引入自定义组件名小写开头 function A() { // 小写开头,React认为它是原生dom节点。babel后 // 为React.createComponent("myComponent",null); // 但因为dom节点中没有myComponent,则报错 return <myComponent></myComponent> }
若你自己是想用ReactComponent,但却一小写开头:
相信若是你们有研究过JavaScript的this
指向问题的话,都知道像下面这种状况,函数中的this指向会丢失:
const a = { func: function () { console.log(this); } } const nextA = a.func; nextA();// 打印undefined(严格模式下) a.func();// 打印{func: f}
这就是你们常说的this指针丢失的问题。
React中的事件绑定也是这样的:
class Foo extends React.Component { handleClick () { this.setState({ xxx: aaa }) } render() { return ( <!-- 在这里我绑定事件未bind(this),结果是当触发click事件,执行handleClick函数时,内部this指向为undefined --> <button onClick={this.handleClick}> Click me </button> ) } }
这是由于onClick={this.handleClick}
其实是分为两步的:
const handleClick = this.handleClick; ...onClick = handleClick
这就发生了上文所说的this指针丢失。
因此必须得在一开始就肯定死this指向,以保证即便执行了const handleClick = this.handleClick;
`...onClick = handleClick`也不会发现this指针丢失的现象。
具体方法有一下两种:
class Foo extends React.Component { handleClick () { this.setState({ xxx: aaa }) } render() { return ( // 在绑定的时候再bind(this)。性能不是很好,多处地方调用同一 // 函数的话,得重复bind <button onClick={this.handleClick.bind(this)}> Click me </button> ) } }
class Foo extends React.Component { constructor () { // 在构造函数里bind(this)。缺点就是写起来不顺手...... // 没有人会习惯在类里声明了函数,再去构造函数里去bind一次把 this.handleClick = this.handleClick.bind(this); } handleClick () { this.setState({ xxx: aaa }) } render() { return ( <button onClick={this.handleClick}> Click me </button> ) } }
除这两种方法,还有一种方法:箭头函数能够解决这一问题(箭头函数的this指向彻底继承于上一做用域的this指向),箭头函数又有两种写法:
class Foo extends React.Component { constructor () { // 在构造函数里bind(this)。缺点就是写起来不顺手...... // 没有人会习惯在类里声明了函数,再去构造函数里去bind一次把 this.handleClick = this.handleClick.bind(this); } handleClick () { this.setState({ xxx: aaa }) } render() { return ( // 至关于每次点击事件的时候就声明一个匿名函数,这个比第一种方法还费性能 <button onClick={e => {this.handleClick}}> Click me </button> ) } }
class Foo extends React.Component { // 这是我最喜欢的写法了,美观而又省性能 handleClick = () => { this.setState({ xxx: aaa }) } render() { return ( <button onClick={this.handleClick}> Click me </button> ) } }
可能你们会想,为何React不本身bind呢?由于每次调用的时候,都bind一次,会影响性能,倒不如一开始就bind好,而后在调用时候直接调用。