@Dale-Lin
2019-03-20T21:11:36.000000Z
字数 5604
阅读 797
Reactjs
React 允许将代码封装成 component,然后像插入普通 HTML 一样,在网页中插入这个组件。
React.createClass
方法用于生成一个组件类:
var HelloMessage = React.createClass(
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
);
ReactDOM.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
上面代码中声明了组件类 HelloMessage
。在模板中插入 <HelloMessage />
时(无子代的组件类可以使用自闭合标签),会自动生成该组件类的一个实例。所有组件类都必须有自己的 render
方法,用于输出组件。
组件类的第一个字母必须大写!
组件类只能包含一个顶层标签!
组件的用法和原生的 HTML 标签完全一致,可以任意加入属性。比如上述代码中,HelloMessage
组件的实例加入了一个 name
属性,值为 John
。
组件的属性可以在组件 类 中的 this.props
对象中获取。如上例使用 this.props.name
获取了组件实例的 name
属性。
作为 JavaScript 保留字的属性有特殊写法:
className
htmlFor
this.props
对象的属性与组件的属性一一对应,例外的是 this.props.children
属性,它表示组件实例的所有子节点:
var NotesList = React.createClass(
render: function() {
return (
<ol>
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
</ol>
)
}
);
ReactDOM.render(
<NoteList>
<span>hello</span>
<span>world</span>
</NoteList>,
document.body
);
上面代码的 NodeList
实例有两个子节点,都可以通过组件类中的 this.props.children
读取。
如果当前组件没有子节点,
this.props.children
为undefined
;如果有一个子节点,数据类型是object
;如果有多个子节点,数据类型是array
。
上例使用了 React 提供的工具方法 React.Children.map(children, function[(thisArg)])
来处理 this.props.children
。
使用这个方法可以遍历 this.props.children
子节点,不用考虑其数据类型。
React 的事件类似 JavaScript 语法中的事件,要注意的是,事件处理函数返回 false 不会阻止事件的冒泡。应该合理使用 e.stopPropagation()
和 e.preventDefault()
来手动设置。
事件处理程序是公用的,事件对象会被复用,在事件处理程序结束后事件对象的所有属性会清除,不能通过异步方式访问事件:
function onClick(event) {
console.log(event); //nullified object.
console.log(event.type); //"click"
const event.type = event.type; //"click"
setTimeout(function() {
console.log(event.type); //null
console.log(eventType); //"click"
}, 0);
//this.setState.clickEvent only contains null values
this.setState({clickEvent: event});
//can still export event properties
this.setState({eventType: event.type);
}
可以调用
event.persist()
将事件从公共池移出,从而异步地访问事件属性。
支持事件:
组件是 virtual DOM 结构,只有插入文档以后才会变成真实的 DOM。
React 中,所有 DOM 变动都先在 virtual DOM 上发生,然后再将实际发生变动的部分,反映在真实 DOM 上(DOM diff)。
在组件类中声明 ref
属性用于获取真实的 DOM 节点:
import React, { Component } from 'react';
class Input extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this); //类的方法默认不绑定 this,为 undefined
}
handleClick(e) {
this.refs.yourInputName.focus();
}
render() {
return {
<div>
<input type="text" ref="yourInputName" />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
};
}
}
在 Input
组件的子节点中,第一个文本输入框用于获取用户的输入;第二个用于聚焦第一个文本框。Virtual DOM 是不能获取用户输入的,要拿到真实的 DOM 节点,在对应的 virtual DOM 元素上要设置一个 ref=[refName]
,其真实的 DOM 节点会保存在 this.refs.[refName]
中。
只有在 virtual DOM 插入文档后才会有该类的真实 DOM,这时才可以访问。
<Component ref={(node) => {this.saveDomNode = node}}/>
如果 ref
属性是一个函数,将会把组件的 DOM 元素作为参数传给这个函数,从而可以获得其引用。
如果把组件看成一个函数,那么它接受了外部参数——props;内部参数为——state,返回一个 virtual DOM 的实现。
当组件实例与用户互动,this.setState
被调用来改变内部状态时,组件和其子组件会尝试重新渲染:
import React, { Component } from 'react';
class Counter extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = { count: 0 };
}
handleClick(e) {
e.preventDefault(); //使用该方法才能阻止默认行为
this.setState({
count: this.state.count + 1
});
}
render() {
return {
<div>
<p>{this.state.count}</p>
<a href="#" onClick={this.handleClick}>Refresh</a>
</div>
};
}
}
参数可以是一个函数(updater):
(prevState, props) => stateChange
其中的 state 对应当前的 state,返回的是重新设置的 state。例如,利用原 state 和 props 设置:
this.setState((prevState, props) => {
return {count: prevState.count + props.step};
});
也可以使用一个对象作为参数:
setState(stateChange)
这样将会把 stateChange
合并到更新的 state 中。
setState 方法调用引起的 React 组件更新四个生命周期函数:
比起修改 props 引发的生命周期少一个 componentWillReceiveProps。
只有 render 调用时,state 才会更新。
React 组件的生命周期分为两类:
组件的挂载又称组件的初始化,有两个生命周期方法:
componentWillMount()
componentDidMount()
componentWillMount()
方法会在 render()
之前执行;componentDidMount()
方法会在 render()
方法后执行,分别代表了渲染前后的时刻。
如果在 componentDidMount()
中执行 setState()
方法,组件会再次更新。一些需要计算组件的位置或宽高时,需要先渲染组件,获取信息再这样重新渲染。
如有需要进行 Ajax 异步处理,也应在这个阶段进行。
组件的卸载只有一个 componentWillUnmount()
状态,常常执行一些清理方法,如事件回收或是清除计时器。
更新过程指父组件向下传递 props
或组件自身执行 setState()
方法时发生的一系列动作。
如果组件自身的 state 更新了,会依次执行:
shouldComponentUpdate(nextProps, nextState)
componentWillUpdate(nextProps, nextState)
render()
componentDidUpdate(prevProps, prevState)
shouldComponentUpdate()
是一个特别的方法,它接收需要更新的 props
和 state
,可以在内部进行判断,让组件在需要更新的时候进行更新。当方法返回 false 的时候,组件不再向下执行生命周期方法。
默认情况下组件会将更新
props
节点的所有子节点重新渲染,因为shouldComponentUpdate()
方法返回 true。无状态组件每次都会重新渲染。
componentWillUpdate(nextProps, nextState)
在渲染前,提供需要更新的 props
和 state
;componentDidUpdate(prevProps, prevState)
在渲染后,提供更新前的 props
和 state
,。
如果组件是由父组件更新 props
而更新的,那么在 shouldComponentUpdate()
之前会先执行 componentWillReceiveProps(nextProps)
。
此方法可以作为 React 组件在 props
传入后,渲染之前 setState()
而不二次渲染的机会。
static getDerivedStateFromProps(nextProps, prevState)
用该方法替换 componentsWillReceiveProps
。
返回值是包含要更新的 state 对象的:
static getDerivedStateFromProps(nextProps, prevState) {
if (nextProps.value !== prevState.value) {
return {
value: nextProps.value,
}
}
return null,
}
在顶层组件以及由于 React 模型所限而不得不操作 DOM 的时候,需要使用 ReactDOM。
DOM 真正被添加到 HTML 中的生命周期方法是 componentDidMount
和 componentDidUpdate
,在这两个方法中可以使用以下两种方法获取真正的 DOM 元素。
要严格限制 DOM 操作场景!
ReactDOM.findDOMNode(component)
当组件渲染到 DOM 中后,findDOMNode
返回该 React 组件实例相应的 DOM 节点。可用于获取表单的 value 以及用于 DOM 的测量。
import React, {Component} from 'react';
import ReactDOM from 'react-dom';
class App extends Component {
componentDidMount() {
//this 指向当前组件实例
const dom = ReactDOM.findDOMNode(this);
}
render() {};
}
如果该实例在 render
中返回 null,那么 findDOMNode
也返回 null,findDOMNode
只对已经挂载的组件有效。
ReactDOM.render(elem, container)
将元素放到 container 里,并返回这个组件的一个引用(无状态组件返回 null)。
ref