React-小记:组件开发注意事项

组件(Component)是React中非常重要的概念,React组件基于jsx语法开发,也就是把HTML写在JS中,刚开始接触的时候还是蛮抵触的,什么都搅在一起感觉挺乱的。不过真正开发起来会发现,只要颗粒度划分合理,一个完整的组件,所有内容都在一个文件中维护是多么方便!

当然你也可以使用工厂方法进行开发,不过个人感觉很不直观且繁琐


基本使用方法

直接引用

1
2
3
4
5
6
7
8
import React from 'react';
import ReactDOM from 'react-dom';
import Button from './component/button.jsx';

ReactDOM.render(
<Button name='Click Me' />,
document.getElementById('index')
);

首先组件import时首字母必须大写,然后通过<组件名 [参数1=值1, 参数2=值2...]/>引用,参数会传入组件的构造函数中
不能在组件引用上绑定事件,即<Button onClick={ clickHandler } />,因为组件引用中除了组件名,其他部分都应该是组件入参。不过可以通过参数的形式将回调函数传到组件内部,然后进行绑定。

组件嵌套

1
2
3
4
5
6
7
8
9
10
import { Component } from 'react';
import Button from './component/botton.jsx';

class DefaultBtn extends Component {
render() {
return <Button name='Default' />;
}
}

export default DefaultBtn;

这里定义了一个新组件DefaultBtn,该组件有引用了一个Button组件,并传入了参数nameDefault


基本写法

无状态的静态组件是最简单的,这里把常用的写法都写下了

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
import { Component } from 'react';

class Button extends Component {
constructor(props) {
super(props);

console.log(this.props.name);
}

buttonClick(e) {
e.preventDefault();
console.log('button clicked!');
}

render() {
let buttonStyle = {
backgroundColor: '#03A9F4',
padding: '3px 20px'
}

return (
<button
className = 'buttonClass'
onClick = { this.buttonClick.bind(this) }
style = { buttonStyle }
>
{ this.props.name }
</button>
);
}
}

export default Button;

不痛不痒的提示

  1. 组件名首字母必须大写
  2. 样式类的属性名是className不是class
  3. 事件绑定通过on+eventType小驼峰写法

    JSX描述DOM时,所有属性都采用小驼峰写法
    这点很棒,一直对DOM中各种方法名时而大写时而小写感到不解,这里全规定为小驼峰写法,顿时顺眼多了

  4. 元素内嵌样式使用对象来描述,样式属性名同样使用小驼峰写法,如backgroundColor
  5. JSX中可以使用{}来写JS语句

几点踩坑点:

React 引入名

在组件中如果引入React,则首字母须大写,也就是说引入React时不可以写成

1
import react form 'react';

在实际项目中,只要入口文件下所依赖的文件有一个进行了正确的import就可以嘞,毕竟webpack最后会把依赖去重。

原因:在编译过程中,组件的许多部分都会转成对React中各个方法的引用,比如:render()return被编译后,实质上返回的是React.createElement(),上文return语句编译后:

1
2
3
4
5
6
7
8
9
return React.createElement(
'botton',
{
className: 'buttonClass',
onClick: this.buttonClick.bind(this)
style: buttonStyle,
},
this.props.name
)


唯一根节点

如果上文你想返回两个button,你可能会这样写:

1
2
3
4
render() {
return (<button>Button1</button>
<button>Button2</button>);
}

BUT,这是不行的,在render()中返回的React元素只能有一个根节点(原因看上文中的React.createElement()),也就是说,你只能这样写:

1
2
3
4
5
6
render () {
return (<div>
<button>Button1</button>
<button>Button2</button>
</div>);
}

莫名其妙多了一层,我也很绝望啊 (。﹏。*)


事件回调中的 this

JSX中给DOM绑定事件时,回调函数默认情况下无法访问当前组件,即回调函数中this不可用,一般情况下我们可以通过bind()来改变函数的上下文来使其可用:

1
onClick = { this.buttonClick.bind(this) }

或者在组件的构造函数中:

1
2
3
4
5
6
7
8
class Button extends React.Component {
constructor(props) {
super(props);

this.buttonClick = this.buttonClick.bind(this);
}
//buttonClick(), render()...
}

或者将事件回调放在一个上下文中:

1
2
3
<button onClick = { () => this.buttonClick() } >
ButtonName
</button>

比较倾向使用第一种方法,毕竟有时候访问this并不是必须的,随用随绑~


事件回调处理

React事件回调函数中,可以显式传入一个合成事件(SyntheticEvent)的实例,他有如下属性与方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
void preventDefault()
boolean isDefaultPrevented()
void stopPropagation()
boolean isPropagationStopped()
DOMEventTarget target
number timeStamp
string type

对于大多数常用事件的处理来说并不会感到有什么不同。不过在开发时还是需要注意,这个实例中封装了一些React特有的事件类型,可能与传统事件的属性与方法并不一一对应。

事件回调需要注意:

  1. 显式传入 Event

    回调函数中须显式传入event参数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    buttonClick() {
    // It doesn't work.
    event.preventDefault();
    console.log(event.type); // => 'react-click'
    }
    buttonClick(event) {
    event.preventDefault();
    console.log(event.type); // => 'click'
    }
  2. 默认事件处理

    从 v0.14 开始,在事件回调函数中return false;将不再阻止事件的传递与元素的默认事件,需要在事件处理函数中手动写上e.stopPropagation()e.preventDefault()

  3. 合成事件无法异步

    为了提高性能,合成事件(SyntheticEvent)是全局的,也就是说实质上只有一个合成事件,默认情况下当回调执行完毕后,所有属性都会被重置以便复用,回调函数中传入的event参数可以看做是他的一个状态,当回调执行完后就会被立刻重置,所以在异步函数中只能访问到被重置后的默认合成事件,而无法访问事件发生时的合成事件。
    1
    2
    3
    4
    buttonClick(event) {
    console.log(event.type); // => 'click'
    setTimeout(() => console.log(event.type), 0); // => null
    }

不过出于特殊考虑,React提供了event.persist()方法使当前事件不被重置,效果类似于深度拷贝了一个对象。
关于事件的其他细节可以参考SyntheticEvent - React

先写这些吧,想起来再补充

所有文章非特别说明皆为原创。技术更迭迅猛,部分内容可能会作修改,为保证信息与源同步,转载时请务必注明文章出处!谢谢合作 :-)