1、组件
组件可以将UI切分成一些的独立的、可复用的部件,这样就只需专注于构建每一个单独的部件。所谓组件,即封装起来的具有独立功能的UI部件。React推荐以组件的方式去重新思考UI构成,将UI上每一个功能相对独立的模块定义成组件,然后将小的组件通过组合或者嵌套的方式构成大的组件,最终完成整体UI的构建。
React认为一个组件应该具有如下特征:
(1)可组合(Composeable):一个组件易于和其它组件一起使用,或者嵌套在另一个组件内部。如果一个组件内部创建了另一个组件,那么说父组件拥有(own)它创建的子组件,通过这个特性,一个复杂的UI可以拆分成多个简单的UI组件;
(2)可重用(Reusable):每个组件都是具有独立功能的,它可以被使用在多个UI场景;
(3)可维护(Maintainable):每个小的组件仅仅包含自身的逻辑,更容易被理解和维护;
2、组件定义
使用函数定义一个组件:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
使用ES6 class定义一个组件:
class Welcome extends React.Component {
render() {
return <h1>Hello World!</h1>;
}
}
3、组件渲染
用户自定义的组件,会将JSX属性作为单个对象传递给该组件,这个对象称之为“props”。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
const element = <Welcome name="Sara" />;
ReactDOM.render(
element,
document.getElementById('root')
);
注意:组件名称必须以大写字母开头。<Welcome />
表示一个组件,并且在使用该组件时你必须定义或引入它。
注意:在添加属性时, class
属性需要写成 className
,for
属性需要写成htmlFor
,这是因为 class 和 for 是 JavaScript 的保留字。
4、复合组件
可以通过创建多个组件来合成一个组件,即把组件的不同功能点进行分离。
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" />
<Welcome name="Cahal" />
<Welcome name="Edite" />
</div>
);
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
注意:组件的返回值只能有一个根元素。这也是我们要用一个<div>
来包裹所有<Welcome />
元素的原因。
5、Props
props 是 React 中另一个重要的概念,它是 properties 的缩写。props 是 React 用来让组件之间互相联系的一种机制,通俗地说就像方法的参数一样。
React 的单向数据流,主要的流动管道就是 props。props 本身是不可变的。当我们试图改变 props 的原始值时,React 会报出类型错误的警告,组件的 props 一定来自于默认属性或通过父组件传递而来。
所有的React组件必须像纯函数那样使用它们的props。props 是不可变的。name 属性通过 this.props.name 来获取。
6、State
React 把组件看成是一个状态机。通过与用户的交互,实现不同状态,然后渲染 UI,让用户界面和数据保持一致。
在React 里,只需更新组件的 state,然后根据新的 state 重新渲染用户界面。
(1)初始化状态
添加一个类构造函数来初始化状态 this.state
:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
类组件应始终使用props调用基础构造函数。构造函数是唯一能够初始化 this.state 的地方。
(2)正确的使用状态
不要直接更新状态:
// Wrong
this.state.comment = 'Hello';
应当使用setState()
来更新状态:
// Correct
this.setState({comment: 'Hello'});
说明:不能在组件内部通过this.state修改状态,因为该状态会在调用setState()后被替换。
setState()并不会立即改变this.state,而是创建一个即将处理的state。setState()并不一定是同步的,为了提升性能React会批量执行state和DOM渲染。
setState()总是会触发一次组件重绘,除非在shouldComponentUpdate()中实现了一些条件渲染逻辑。
7、组件的生命周期
组件的生命周期可分成三个状态:
- Mounting:已插入真实 DOM
- Updating:正在被重新渲染
- Unmounting:已移出真实 DOM
生命周期的方法有:
- componentWillMount 在渲染前调用,在客户端也在服务端。
- componentDidMount : 在第一次渲染后调用,只在客户端。之后组件已经生成了对应的DOM结构,可以通过this.getDOMNode()来进行访问。 如果你想和其他JavaScript框架一起使用,可以在这个方法中调用setTimeout, setInterval或者发送AJAX请求等操作(防止异步操作阻塞UI)。
- componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
- shouldComponentUpdate 返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。
- componentWillUpdate在组件接收到新的props或者state但还没有render时被调用。在初始化时不会被调用。
- componentDidUpdate 在组件完成更新后立即调用。在初始化时不会被调用。
- componentWillUnmount在组件从 DOM 中移除的时候立刻被调用。
方法中带有前缀 will 的在特定环节之前被调用,而带有前缀 did 的方法则会在特定环节之后被调用。
8、组件传值
(1)父组件向子组件传值
父组件通过属性的形式向子组件传递参数,子组件通过props接收父组件传递的参数。
//A.js
class WelcomeA extends React.Component {
render() {
return (
<div>
<WelcomeB userName='Tom'/>
</div>
)
}
}
//B.js
class WelcomeB extends React.Component {
render() {
return <h1>{this.props.userName}</h1>;
}
}
(2)子组件向父组件传值
子组件要和父组件通信,子组件需要调用父组件传递过来的方法
//A.js
class WelcomeA extends React.Component {
handleDelete(param) {
console.log(param);
}
render() {
return (
<div>
<WelcomeB
delete={this.handleDelete.bind(this)}
userName='Tom'/>
</div>
)
}
}
//B.js
class WelcomeB extends React.Component {
handleDelete(){
this.props.delete('delete');
}
render() {
return <h1 onClick={this.handleDelete.bind(this)}>{this.props.userName}</h1>;
}
}