一、组件的创建方式
类组件
可以通过ES6中的类来创建组件,该类继承
React.Component
,并且拥有一个render()
函数,该函数的作用于函数组件的那个函数一样,用于返回一个JSX
。
class Clock extends React.Component {
// render函数表示渲染,每次重新渲染都要调用该函数
render(){
return ( <div>
<h2>Clock, {this.props.name}</h2>
</div>
);
}
}
二、组件的内部状态
1.state
state
是组件内部维护的一组用于反映组件UI
变化的状态集合
。state
需要在构造函数中进行初始化,如果要在组件类中重写构造函数,那么需要在构造函数的第一行显式调用super(props)
。
class Clock extends React.Component {
constructor(props){
super(props);
this.state = {
now:new Date().toLocaleString()
};
}
}
2.state特点
不能直接修改state,需要调用
this.setState()
方法进行修改。
修改的时候要注意:
- 状态的类型是不可变类型:直接赋新值
- 状态的类型是数组:通过
concat
方法或者ES6数组拓展语法,不能使用在原数组的基础上修改
的方法,例如push
之类 - 状态的类型是普通对象:通过
Object.assgin
或者对象拓展语法 state
的更新是异步
的调用setState
,组件的state
并不会立即改变state
的更新是一个浅合并的过程
3.示例
class Mystates extends React.Component{
constructor(props) {
super(props);
this.state = {arr:[1,2,3],obj:{name:'tom',age:28}};
}
//在组件将要被挂载前调用
componentWillMount() {
//在原先的数组之上追加数据
this.setState({arr:this.state.arr.concat(4),obj:Object.assign({},this.state.obj,{name:'yoo',age:27,gender:'man'})});
}
render(){
return (
<div>
<h3>{this.state.arr.toString()}---{JSON.stringify(this.state.obj)}</h3>
</div>
);
}
}
三、组件的生命周期
1.生命周期图
2.生命周期
- componentWillMount
在组件将要被挂载前调用 - componentDidMount
在组件挂载后(插入DOM 树
中)立即调用。依赖于DOM 节点
的初始化应该放在这里。如需通过网络请求获取数据,此处是实例化请求的好地方。如果调用setState
,然后可以再次渲染,但是这次渲染会发生在浏览器更新屏幕之前,用户不会发现中间状态。 - shouldComponentUpdate
组件是否被更新,如果返回true
则更新(默认),否则不更新。 - componentWillUpdate
组件将要被更新 - componentDidUpdate
组件被更新。会在更新后会被立即调用。首次渲染不会执行此方法。如果你对更新前后的props
进行了比较,也可以选择在此处进行网络请求。 - componentWillUnmount
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作。componentWillUnmount()
中不应调用setState()
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
3.示例
class Live extends React.Component {
constructor(props) {
super(props);
this.state = {
msg: 'hello world',
};
}
//在组件将要被挂载前
componentWillMount() {
console.log(this.state);
}
//组件挂载完毕
componentDidMount() {
//修改数据
setTimeout(() => {
this.setState({
msg: 'wonderful world'
});
}, 2000);
console.log(this.state,'+++');
}
//是否可以更新
shouldComponentUpdate() {
//返回true更新(默认值),返回false不更新也不会再渲染在页面上
return true;
}
//将要更新
componentWillUpdate(){
alert(1);
}
componentDidUpdate() {
alert(2);
}
componentWillUnmount() {
console.log('将要被卸载');
}
render(){
console.log('render----');
return (
<h3>{this.state.msg}</h3>
);
}
}
四、事件机制
1.事件绑定
与
vue
绑定方式类似,比如绑定点击事件需要在组件上通过onClick
来实现,事件处理函数必须在大括号内通过this
来指定。事件处理函数应该定义在类中,与render()
函数在同一级别。
class MyComponent extends React.Component{
handleClick(){
alert('handleClick...');
}
render(){
return (
<div onClick={this.handleClick}>hello MyComponent</div>
);
}
}
2.事件对象
与
DOM
中的事件类似,通过事件对象获取目标元素,默认情况下,可以通过在事件处理函数上声明形式参数来获取event
。你可以在调用event.preventDefault()
来阻止默认行为,调用event.target
获取目标元素,调用event.cancelable
阻止事件冒泡。
class MyComponent extends React.Component{
handleClick(event){
alert('handleClick...');
}
render(){
return (
<div onClick={this.handleClick}>hello MyComponent</div>
);
}
}
3.this指针
如果通过es6的函数声明方式来定义事件处理函数,那么在事件处理函数中的
this
为undefined
。我们可以用箭头函数
来定义事件处理函数,这时候箭头函数中的this
指向组件对象
。
class MyComponent extends React.Component{
handleClick = (event)=>{
alert('handleClick...');
console.log(this);
}
render(){
return (
<div onClick={this.handleClick}>hello MyComponent</div>
);
}
}
4.参数传递方式1
如果想要传递参数给事件处理函数,需要在事件绑定的时候调用
bind()
方法,然后将this
作为第一个实参,其他的参数可以自定义。但是要注意,在事件处理函数中,第一个参数为你绑定的第二个形参,… ,最后一个参数为event
对象。
class MyComponent extends React.Component{
handleClick = (param,event)=>{
alert('handleClick...');
console.log(this);
}
render(){
return (
<div onClick={this.handleClick.bind(this,1)}>hello MyComponent</div>
);
}
}
5.参数传递方式2
也可以使用
箭头函数
传参。
class MyComponent extends React.Component{
handleClick = (p1,p2,event)=>{
alert('handleClick...');
console.log(event);
}
render(){
return (
<div onClick={(e)=>this.handleClick(1,2,e)}>hello MyComponent</div>
);
}
}
6.示例
//事件绑定
class MyEvent extends React.Component{
constructor(props) {
super(props);
this.state = {
msg: 'hello',
};
}
//箭头函数
handle1 = (event)=>{
console.log(event);
console.log(this);
this.setState({
msg:'msg'
});
}
//函数声明
handle2(event){
console.log(event);
console.log(this);
this.setState({
msg: 'msg'
});
}
//上面两种事件处理函数功能一样
render(){
return (
<div>
{/*方法一:使用箭头函数声明事件处理程序可以解决内部this指向的问题*/}
<button onClick={this.handle1}>点击{this.state.msg}</button>
{/*方法二:使用bind()方法*/}
<button onClick={this.handle1.bind(this)}>点击{this.state.msg}</button>
<button onClick={this.handle2.bind(this)}>点击{this.state.msg}</button>
{/*方法三:使用箭头函数*/}
<button onClick={(event)=>{this.handle1(event)}}>点击{this.state.msg}</button>
<button onClick={(event)=>{this.handle2(event)}}>点击{this.state.msg}</button>
</div>
);
}
}
//事件传参
class MyTest extends React.Component{
//箭头函数方式
handle1 = (a,b,event) => {
console.log(event.target.getAttribute('data-id'));
console.log(a,b,event);
}
//函数声明方式
handle2(a,b,event){
console.log(event.target.getAttribute('data-id'));
console.log(a,b,event);
}
//上面两种事件处理函数功能一样
render(){
return (
<div>
{/*用bind()方法绑定事件传参*/}
<button data-id='1001' onClick={this.handle1.bind(this,1002,1003)}>点击</button>
<button data-id='1001' onClick={this.handle2.bind(this,1002,1003)}>点击</button>
{/*用箭头函数传参*/}
<button data-id='1001' onClick={(e)=>{this.handle1(1002,1003,e)}}>点击</button>
<button data-id='1001' onClick={(e)=>{this.handle2(1002,1003,e)}}>点击</button>
</div>
);
}
}
五、Ref
1.介绍
React提供的这个ref属性,表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例。ref属性可以挂载到组件上也可以是dom元素上。Refs 提供了一种方式,允许我们访问 DOM 节点或在 render 方法中创建的 React 元素。
ref 属性接受一个回调函数,它在组件被加载或卸载时会立即执行,回调函数的参数为该组件的真正实例的引用;ref属性接受一个字符串,例如foo,通过this.refs.foo来访问该组件真正实例。
class MyRefs extends React.Component{
constructor(props) {
super(props);
this.state = {
msg:'123'
};
}
componentDidMount() {
//this.refs保存该组件内有ref属性并且属性值为字符串的元素
console.log(this.refs);
console.log(this.refs.hello);
console.log(this.refs.world);
}
courseFormRefs(n){
console.log("ref参数",n);
}
render(){
return (
<div>
<h3 ref="hello">{this.state.msg}</h3>
<h3 ref="world">hello</h3>
<h3 ref={(node)=>{console.log(node);}}>ref值为回调函数</h3>
<h3 ref={this.courseFormRefs}>hello</h3>
</div>
);
}
}
2.何时使用 Refs
- 管理焦点,文本选择或媒体播放
- 触发强制动画
- 集成第三方 DOM 库
3.创建 Refs
Refs 是使用 React.createRef() 创建的,并通过 ref 属性附加到 React 元素。在构造组件时,通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return <div ref={this.myRef} />;
}
}
4.访问 Refs
当 ref 被传递给 render 中的元素时,对该节点的引用可以在 ref 的 current 属性中被访问。
const node = this.myRef.current;
ref 的值根据节点的类型而有所不同:
- 当 ref 属性用于 HTML 元素时,构造函数中使用 React.createRef() 创建的 ref 接收底层 DOM 元素作为其 current 属性
- 当 ref 属性用于自定义 class 组件时,ref 对象接收组件的挂载实例作为其 current 属性。
- 不能在函数组件上使用 ref 属性,因为他们没有实例
5.父组件改子组件state数据
在父组件获取子组件实例 refs,再调用 setState() 更改子组件state数据。
父组件
import React,{Component} from 'react';
import ChildrenComponent from './ChildrenComponent';
class ParentComponent extends Component{
changeChildState = ()=>{
const child = this.refs.child;
console.log(child.state.childrenMsg);
child.setState({
childrenMsg:'childrenHello'
});
}
render(){
return (
<div>
<button onClick={this.changeChildState}>点击更改子组件中state中childrenMsg</button>
<ChildrenComponent ref="child" />
</div>
);
}
}
export default ParentComponent;
子组件
import React,{Component} from 'react';
class ChildrenComponent extends Component {
constructor(props) {
super(props);
this.state = {
childrenMsg: 'childrenMsg'
};
}
render() {
return (
<div>
<h3>子组件state中的数据:{this.state.childrenMsg}</h3>
</div>
);
}
}
export default ChildrenComponent;
6.子组件改父组件state数据
需要父组件传递修改自己state的函数给子组件调用。
父组件
import React,{Component} from 'react';
import ChildrenComponent from './ChildrenComponent';
class ParentComponent extends Component{
constructor(props) {
super(props);
this.state = {
parentMsg: 'parentMsg'
};
}
changeParentState = ()=>{
this.setState({
parentMsg:'parentHello'
});
}
render(){
return (
<div>
<ChildrenComponent ref="child" parentMsg={this.state.parentMsg} changeParentState={this.changeParentState}/>
</div>
);
}
}
export default ParentComponent;
子组件
import React,{Component} from 'react';
class ChildrenComponent extends Component {
render() {
return (
<div>
<h3>接受父组件state中的数据:{this.props.parentMsg}</h3>
<button onClick={this.props.changeParentState}>更改父组件中的数据</button>
</div>
);
}
}
export default ChildrenComponent;
7.在jsx中添加样式
1.添加行内样式
注意:
- 应使用 className 属性来引用外部 CSS 样式表中定义的 class
- style 接受一个采用小驼峰命名属性的 JavaScript 对象,而不是 CSS 字符串
- 样式不会自动补齐前缀。如需支持旧版浏览器,请手动补充对应的样式属性
import React,{Component} from 'react';
class Style extends Component{
render(){
const btnStyle = {background:'teal',width:100,border:'none',fontSize:30,color:'white',borderRadius:5};
return (
<div className="Style">
<span style={{color:'red',fontSize:40}}>hello</span>
<button style={btnStyle}>按钮</button>
</div>
);
}
}
export default Style;
React 会自动添加 ”px” 后缀到内联样式为数字的属性后。如需使用 ”px” 以外的单位,请将此值设为数字与所需单位组成的字符串。但并非所有样式属性都转换为像素字符串。有些样式属性是没有单位的(例如 zoom,order,flex)。无单位属性的完整列表在此处。
// Result style: '10px'
<div style={{ height: 10 }}>
Hello World!
</div>
// Result style: '10%'
<div style={{ height: '10%' }}>
Hello World!
</div>
2.引入外部样式
import React,{Component} from 'react';
//引入外部样式
import './3-Style.css';
class Style extends Component{
render(){
return (
<div className="Style">
<h3>world</h3>
</div>
);
}
}
export default Style;
css
.Style h3{
color: cornflowerblue;
font-size: 40px;
margin: 0;
}