react从0到1的探索记录02

9、在react中如何创建组件

ES6中class关键字的作用
  • class关键字中构造器constructor的了解和基本使用
//console.log('123')
//构造函数创建一个类
function Person(name,age){
    this.name = name;
    this.age = age;
}
const p1= new Person('tom',25);
//直接挂载到构造函数的属性,称为静态属性
Person.info = '这是一个人的类';
console.log(p1);
//通过new出来的实例访问到的属性,称为实例属性
console.log(p1.name);
console.log(p1.age);
//访问静态属性不能通过实例,要通过构造函数
console.log(p1.info);//undefined
console.log(Person.info);

//分割线
console.log('---------------------------------------------')
//使用class关键字创建类
//class创建的类的{}中,只能写构造器,静态属性,实例属性,静态方法和实例方法
//另外class关键字内部本质还是构造函数的原理来实现的,这里的class可以看作是语法糖。
class Animal{
    //constructor是类的构造器 每一个类中都有一个构造器,如果没有人为指定构造器的话,那么类内部的构造器可以认为是个空构造器 constructor(){}
    //构造器的作用,当执行new一个实例的时候,必然优先执行构造器中的代码
    constructor(name,age){
        //实例属性
        this.name = name;
        this.age = age;
    }
    //在class内部创建静态属性,使用static关键字
    static info='这是一个动物的类'
   
}
const animal1 = new Animal('旺财',2);
console.log(animal1);
console.log(animal1.name);
console.log(animal1.age);
//访问静态属性同样要通过类
console.log(animal1.info);//undefined
console.log(Animal.info);
  • 实例属性和实例方法,静态属性和静态方法
function Person(name,age){
    //实例属性
    this.name = name;
    this.age = age;
}
//静态属性
Person.info = '这是个人的类';

//添加一个实例方法
Person.prototype.say = function(){
    console.log('你好')
}
//添加一个静态方法
Person.show = function(){
    console.log('这是静态方法')
}
const p1 = new Person('tom',20);
console.log(p1);
p1.say();//调用实例方法
//p1.show();//报错
Person.show();//调用静态方法

console.log('---------------------------------------------------')
//class创建类

class Animal{
    constructor(name,age){
    //实例属性
        this.name = name;
        this.age = age;
    }
    //静态属性
    static info = '这是动物类'
    //添加实例方法
    say(){
        console.log('动物类的实例方法')
    }
    //添加静态方法
    static show(){
        console.log('这是动物类的静态方法')
    }

}
const animal1 = new Animal('阿黄',3);
console.log(animal1);
//调用实例方法
animal1.say();
//调用静态方法
Animal.show();
  • 使用extends来实现继承
    创建两个类
//创建一个美国人的类
class American{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
}
const A1 = new American('jack',25);
console.log(A1);

//创建一个中国人的类
class Chinese{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
}
const C1 = new Chinese('林书豪',30);
console.log(C1);

为两个类创建父类并实现继承,以及子类自定义构造器时super的调用

//为类American和Chinese创建一个父类这里可以将其视为该两个类的原型对象 prototype
class Person{
    constructor(name,age){
        this.name = name;
        this.age = age;
    }
    //添加实例方法
    say(){
        console.log('你好')
    }
}

//创建一个美国人的类
//class类中,可以使用extends实现子类继承父类 语法 class 子类 extends 父类 {}
class American extends Person{
}
const A1 = new American('jack',25);
console.log(A1);
A1.say();

//创建一个中国人的类
class Chinese extends Person{
    //如果此时不定义该类的construntor,那么该类的constructor其实就是父类的constructor,如果此处定义该类的constructor,那么需要使用函数super()
    constructor(name,age,IDcard){
        super(name,age)
        this.IDcard = IDcard
    }
    //3个问题
    //1.为什么要在constructor中使用super()?如果一个子类通过extends关键字继承父类,那么在该子类自定义constructor时,必须先调用super;
    //2.super是什么? super是一个函数,其本质是父类的构造器,子类的super()其实是父类构造器constructor在子类的引用。
    //3.调用了super后参数的传递?在定义类的constructor时可以为该类添加有别于父类实例属性的,
    //并且仅属于该类的实例属性(比如该例下的IDcard属性),但是为了保证同样拥有父类定义的实例属性,需要传必要的参数,如这里传递的name,age,否则对应属性就是undefined.

}
const C1 = new Chinese('林书豪',30,375435199389987654);
console.log(C1);
C1.say();
创建组件的第二种方式
类比以上,使用class关键字来创建react的组件
//如果要使用class来定义组件,必须让组件继承React.Component
class 组件名 extends React.Component{
          //  组件内部必须使用render函数
          render(){
                //render函数中必须返回符合jsx语法的虚拟Dom结构或null
                return 
这是由class类创建的组件
} }
class类创建的第一个react组件
import React from 'react'
//以上等同于 import React,{Component} from 'react'
import ReactDom from 'react-dom'

//class创建一个组件
class Onecomponent extends React.Component{
    //render函数用来渲染当前组件对应的虚拟Dom元素
    render(){
        //return null
        return 
我是第一个用class类创建出来的react组件
} } //调用ReactDom render函数来渲染 ReactDom.render(
,document.getElementById('app'))

10、两种创建组件的方式的对比

使用class关键字创建的组件,有自己的私有数据和生命周期函数,而使用构造函数创建的组件,只有props,没有自己的私有数据和生命周期函数。
1、使用构造函数创建出来的组件是无状态组件。
2、使用class关键字创建出来的是有状态组件,在react中使用往往更多。
有状态组件和无状态组件的主要区别就是有无state属性和生命周期函数。
3、两种创建组件的方式的选择,什么时候使用?
如果一个组件需要有自己的私有数据,推荐使用class创建的有状态组件。
如果一个组件不需要有自己的私有数据,那么可以使用无状态组件,同时,因为构造函数创建的组件没有自己的私有数据和生命周期函数,运行效率相较于class创建的组件较高。
4、props和state的区别

  • props中的数据是外界传递的,而state中的数据是组件私有的(通过ajax获取到的数据一般都是私有数据)
  • props中的数据只读无法被修改,而state中的数据可读可写。
import React from 'react'
//以上等同于 import React,{Component} from 'react'
import ReactDom from 'react-dom'

//class创建一个组件
class Onecomponent extends React.Component{
    constructor(){
        super()
        //this.state在这里就相当于vue中的data(){return{}}
        this.state = {
            message:'我是class关键字创建的组件的私有数据'
        }
    }
    //render函数用来渲染当前组件对应的虚拟Dom元素
    render(){
        //return null
        //this.props.name = 'jack' 试图修改props的属性 会报错 。无论是使用class关键字创建的组件还是使用构造函数创建的组件 props都是只读的不可修改其属性。
        //class创建的组件的私有数据是可以被修改的,它是可读可写的
        this.state.message = '我被修改了'
        //class关键字创建的组件在使用外界的参数时,不需要接受,直接使用this.props.属性名即可访问,this代表的是当前组件创建的实例对象
        return 
我是第一个用class类创建出来的react组件---{this.props.name}-----{this.props.age}------{this.state.message}
} } const user = { name:'tom', age:20 } //调用ReactDom render函数来渲染 ReactDom.render(
,document.getElementById('app'))

11、使用组件创建一个评论列表

如图:
react从0到1的探索记录02_第1张图片
评论列表
import React from 'react'
import ReactDom from 'react-dom'


class Pinglun extends React.Component{
    constructor(){
        super()
        this.state = {
            TextList:[
                {id:0,name:'张三','words':'哈哈,沙发'},
                {id:1,name:'李四','words':'哈哈,板凳'},
                {id:2,name:'王五','words':'哈哈,凉席'},
                {id:3,name:'赵六','words':'哈哈,砖头'},
                {id:4,name:'田七','words':'哈哈,楼下山炮'}
            ]
        }
    }
    render(){
        return 

这是一个评论列表

{this.state.TextList.map(item=>

评论人:{item.name}

评论内容:{item.words}

)}
} } ReactDom.render(
,document.getElementById('app'))

以上可以进一步处理如下(将列表结构抽离为一个无状态组件):

import React from 'react'
import ReactDom from 'react-dom'

//构造函数创建一个无状态组件应用于评论列表(组件的嵌套)
function Getpinglun(props){
    return 

评论人:{props.name}

评论内容:{props.words}

} class Pinglun extends React.Component{ constructor(){ super() this.state = { TextList:[ {id:0,name:'张三','words':'哈哈,沙发'}, {id:0,name:'李四','words':'哈哈,板凳'}, {id:0,name:'王五','words':'哈哈,凉席'}, {id:0,name:'赵六','words':'哈哈,砖头'}, {id:0,name:'田七','words':'哈哈,楼下山炮'} ] } } render(){ return

这是一个评论列表

{this.state.TextList.map(item=>)}
} } ReactDom.render(
,document.getElementById('app'))

进一步简化,将两个组件均抽离为单独的模块(两个单独的jsx文件),如下:
index.js文件

import React from 'react'
import ReactDom from 'react-dom'
//导入Pinglun组件
import Pinglun from './component/Pinglun'
//如果在webpack.config.js中配置了路径 那么还可以使用别名来引入 如import Pinglun from '@/component/Pinglun'


ReactDom.render(
,document.getElementById('app'))

Pinglun.jsx文件

import React from 'react'
//导入组件Getpinglun
import Getpinglun from './Getpinglun'
//如果在webpack.config.js中配置了路径 那么还可以使用别名来引入 如import Getpinglun from '@/component/Getpinglun'

export default class Pinglun extends React.Component{
    constructor(){
        super()
        this.state = {
            TextList:[
                 {id:0,name:'张三','words':'哈哈,沙发'},
                {id:0,name:'李四','words':'哈哈,板凳'},
                {id:0,name:'王五','words':'哈哈,凉席'},
                {id:0,name:'赵六','words':'哈哈,砖头'},
                {id:0,name:'田七','words':'哈哈,楼下山炮'}
            ]
        }
    }
    render(){
        return 

这是一个评论列表

{this.state.TextList.map(item=>)}
} }

Getpinglun.jsx文件

import React from 'react'
export default function Getpinglun(props){
     return 

评论人:{props.name}

评论内容:{props.words}

}

12、为创建的组件添加样式

添加普通的内联样式 比如在Pinglun.jsx中
import React from 'react'
//导入组件Getpinglun
import Getpinglun from './Getpinglun'
//如果在webpack.config.js中配置了路径 那么还可以使用别名来引入 如import Getpinglun from '@/component/Getpinglun'

export default class Pinglun extends React.Component{
    constructor(){
        super()
        this.state = {
            TextList:[
                {id:0,name:'张三','words':'哈哈,沙发'},
                {id:0,name:'李四','words':'哈哈,板凳'},
                {id:0,name:'王五','words':'哈哈,凉席'},
                {id:0,name:'赵六','words':'哈哈,砖头'},
                {id:0,name:'田七','words':'哈哈,楼下山炮'}
            ]
        }
    }
    render(){
        return 
{/* jsx语法中如果想加入行内样式那么应该照如下语法来写,属性值不是数字的要加引号,数字不需要 */}

这是一个评论列表

{this.state.TextList.map(item=>)}
} }
但一般不会直接在组件虚拟Dom结构添加这样的内联样式,会做一定处理,比如在Getpinglun.jsx中
import React from 'react'

//jsx中写行内样式
// export default function Getpinglun(props){
//     {/* jsx语法中如果想加入行内样式那么应该照如下语法来写,属性值不是数字的要加引号,数字不需要 */}
//     return 
//

评论人:{props.name}

//

评论内容:{props.words}

//
// } //如果向上面这样写样式,反而会让结构看起来更加混乱因此可以将样式进行一下简单的封装处理 如下 // const divstyle = {border:'1px solid #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'}; // const hstyle = {fontSize:'16px'}; // const pstyle = {fontSize:'12px'}; // export default function Getpinglun(props){ // return
//

评论人:{props.name}

//

评论内容:{props.words}

//
// } //可以进一步做如下处理 // const styles = { // divstyle:{border:'1px solid #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'}, // hstyle:{fontSize:'16px'}, // pstyle:{fontSize:'12px'} // } // export default function Getpinglun(props){ // return
//

评论人:{props.name}

//

评论内容:{props.words}

//
// } //进一步将styles抽离为一个单独的样式模块 如下 //引入抽离出去的styles.js import styles from '@/component/styles' export default function Getpinglun(props){ return

评论人:{props.name}

评论内容:{props.words}

}

styles.js文件如下

export default {
    divstyle:{border:'1px solid #ccc',margin:'10px',padding:'10px',boxShadow:'0 0 10px #ccc'},
    hstyle:{fontSize:'16px'},
    pstyle:{fontSize:'12px'}
}

添加外联的样式表.css,启用css模块化,并且自定义生成类名的格式。比如,在组件Pingluntwo.jsx中引用pinglun.css

pinglun.css

.title{
    font-size:16px;
    text-align:center;
    font-weight:200;
}
/*css模块化处理只能够处理类选择器和id选择器,对于标签是无效的*/

/*通过local和global来设置类名是否被模块化,默认是所有类名和id都是local,可以被模块化,而设置了global后,则不会被模块化,会全局生效*/
:global(.test){
    color:yellow;
}

将以上css样式表导入到Pingluntwo.jsx组件中

import React from 'react'
//导入组件Getpinglun
import Getpingluntwo from './Getpingluntwo'
//如果在webpack.config.js中配置了路径 那么还可以使用别名来引入 如import Getpinglun from '@/component/Getpinglun'
//导入外部样式表
import classObj from '@/component/pinglun.css' 
//导入之后在运行之前需要安装来解析css的依赖并在webpack.config.js中配置好 npm install style-loader css-loader -D 否则无法解析css
//导入的该样式表会对该组件下包括嵌套组件都起作用,所以为了保证不会对其他结构产生影响,需要做进一步的处理 这里的处理方法往往就是对样式表进行模块化处理(同样在webpack.config.js进行处理)
//webpack.config.js中 {test: /\.css$/,use:['style-loader','css-loader?modules']}在css-loader后通过?添加参数modules,表示为普通的样式表,启用模块化。
//或者采用{test:/\.css$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:true}}]}的方式来为css开启模块化。
//还可以通过添加其他参数做如下配置{test:/\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']}或者{test:/\.css$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:{localIdentName:'[path][name]-[local]-[hash:base64:5]'}}}]}为模块化的css自定义生成类名的格式有效避免类名的重复。


//引入的外部框架的css在webpack.config.js文件中设置不对其进行模块化处理的方式如下

//有的时候需要在项目中使用其他的框架的ui,比如使用bootstrap.css,如果引用的外部其他框架的css进入项目,那么由于webpack.config.js中的配置
//也会对引入的css也进行模块化处理,模块化之后,在引用该css样式中的类时,通过访问属性的方式来为相关元素添加类名就显得及其繁琐,这时候,可以做其他处理 如下:
//将自己的样式表改为以scss或者less为结尾的文件,安装处理less或sass的依赖,并在webpack.config.js中配置好 npm install sass-loader node-sass  -D
//{test:/\.scss$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:{localIdentName:'[path][name]-[local]-[hash:base64:5]'}}},{loader:'sass-loader'}]}在css-loader后通过配置相关参数为普通的样式表启用模块化,并且自定义生成类名的格式
//并在webpack.config.js中将css配置为{test:/\.css$/,use:['style-loader','css-loader]} 这样就可以像正常一样使用外部引入的css了,如 而将自己定义的css后缀改为scss不会受到影响
//Sass是成熟、稳定、强大的CSS预处理器,而SCSS是Sass3版本当中引入的新语法特性,完全兼容CSS3的同时继承了Sass强大的动态功能。


//在引用某个包的时候,如果这个包安装到了node_modules中,在其他组件使用的时候,可以直接以包名引入自己的模块。


export default class Pinglun extends React.Component{
    constructor(){
        super()
        this.state = {
            TextList:[
                {id:0,name:'张三','words':'哈哈,沙发'},
                {id:0,name:'李四','words':'哈哈,板凳'},
                {id:0,name:'王五','words':'哈哈,凉席'},
                {id:0,name:'赵六','words':'哈哈,砖头'},
                {id:0,name:'田七','words':'哈哈,楼下山炮'}
            ]
        }
    }
    render(){
        return 
{/*在需要的标签上,使用className指定模块化的样式*/} {/*

这是一个评论列表

*/} {/*

这是一个评论列表

或者如下 */}

这是一个评论列表

{this.state.TextList.map(item=>)}
} }

getpinglun.css

.title{
    font-size: 14px;
}
.content{
    font-size:12px;
}
#box{
    border:1px solid #ccc;
    margin:10px;
    padding:10px;
    box-shadow:0 0 10px #ccc;
}

将getpinglun.css导入到Getpingluntwo.jsx中

import React from 'react'
import objtwo from '@/component/getpinglun.css'
export default function Getpinglun(props){
    return 

评论人:{props.name}

评论内容:{props.words}

}
说明
  • webpack4.x中启用css模块化,配置方式如下:
{test: /\.css$/,use:['style-loader','css-loader?modules']}
或者{test:/\.css$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:true}}]}

此外,一般还会添加其他参数来自定义生成的类名的格式。
使用localIdentName自定义生成的类名格式,可选的参数有:
[path] 表示样式表 相对于项目根目录 所在路径
[name] 表示 样式表文件名称
[local] 表示样式的类名定义名称
[hash:length] 表示32位的hash值
所以为css样式表启用模块化并且来自定义生成的类名时一般在webpack.config.js中做如下配置:

 {test:/\.css$/,use:['style-loader','css-loader?modules&localIdentName=[path][name]-[local]-[hash:5]']}
//如果上面的配置无法使用还可以如下配置
{test:/\.css$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:{localIdentName:'[path][name]-[local]-[hash:base64:5]'}}}]}
  • 使用 :local() 和 :global()
    :local()包裹的类名,是被模块化的类名,只能通过className={cssObj.类名}来使用
    :local默认可以不写,这样,默认在样式表中定义的类名,都是被模块化的类名
    :global()包裹的类名,是全局生效的,不会被 css-modules 控制,定义的类名是什么,就是使用定义的类名className="类名"
    css模块化处理只能够处理类选择器和id选择器,对于标签是无效的

在项目中启用模块化并同时使用其他框架的样式表比如使用bootstrap的css

引入的外部框架的css在webpack.config.js文件中设置不对其进行模块化处理的方式如下

有的时候需要在项目中使用其他的框架的ui,比如使用bootstrap.css,如果引用的外部其他框架的css进入项目,那么由于webpack.config.js中的配置,也会对引入的css也进行模块化处理,模块化之后,在引用该css样式中的类时,通过访问属性的方式来为相关元素添加类名就显得及其繁琐,这时候,可以做其他处理 如下:

1、把 自己的样式表,定义为 .scss 文件。
2、第三方的 样式表,还是 以 .css 结尾。
3、我们只需要为自己的 .scss 文件,启用模块化即可。
4、运行npm install sass-loader node-sass -D 安装能够解析scss文件的loader。
5、webpack.config.js中添加loader规则如下:
{test:/\.scss$/,use:[{loader:'style-loader'},{loader:'css-loader',options:{modules:{localIdentName:'[path][name]-[local]-[hash:base64:5]'}}},{loader:'sass-loader'}]}, //添加打包处理 scss 文件的 loader

通过以上处理之后就会只对自己的css(添加了.scss)的样式表进行模块化处理,对于第三方的样式表不会模块化, 这样就可以像正常一样使用第三方的css了,如 ,引用bootstrap的btn样式。

Sass是成熟、稳定、强大的CSS预处理器,而SCSS是Sass3版本当中引入的新语法特性,完全兼容CSS3的同时继承了Sass强大的动态功能。

13、React事件的绑定

  • 事件的名称是react提供的,事件名的首字母大写,并且遵循驼峰命名规范。
  • 为事件提供的处理函数,必须如下
onClick = {function}
react中常用的事件绑定方式如下
import React from 'react'

export default class BindEvent extends React.Component{
    constructor(){
        super()
        this.state = {}
    }
    render(){
        return 
我是BindEvent组件
{/* 在react中有一套自己的事件绑定机制,事件名小驼峰命名,参数必须为一个函数*/} {/* */} {/* */} {/* */} {/* 调用该实例对象下的clickEvent方法,点击才会执行 */} {/* */} {/* 调用该实例对象下的clickEvent方法,初始化时就开始执行一次 */} {/* */} {/* react中绑定事件常用方式(箭头函数) 箭头函数内部,this指向外部环境的this,因此这里的this指向的是该实例 */}
} // clickEvent(){ // console.log('哈哈哈哈哈') // } //将clickEvent改变为一个箭头函数 clickEvent=()=>{ console.log('哈哈哈哈') } }
react中修改state中的数据,推荐使用this.setState({ }),如下
import React from 'react'

export default class BindEventTwo extends React.Component{
    constructor(){
        super();
        this.state = {
            message:'哈哈哈哈哈',
            name:'tom',
            age:20
        }
    }
    render(){
        return 

{this.state.message}

} changeState=(n1,n2)=>{ //这里的n1,n2是接收的调用该方法时的参数 //在react,想要修改或者为state重新赋值,不能使用this.state.xxxx = 值的方式,应该调用react提供的this.setState({属性:值})的方式 this.setState({ message:'我被修改了'+n1+n2 },function(){ //修改状态值后的回调 console.log(this.state.message) }) //在React中推荐使用this.setState({})来修改状态值,并且在setState中,只会把对应的state状态更新,而不会覆盖其他的state状态 //另外this.setState是一个异步的操作,所以在通过这种方式修改state后,如果希望第一时间得到修改过后的状态值,需要在this.setState({},callback)执行回调函数callback这里获取 } }
在React中实现类比Vue中的数据的双向绑定
  • Vue中提供了v-model指令来实现数据的双向绑定。
  • 在React中,默认是单向数据流,只能够把state中的数据绑定到页面,无法把页面中数据的变化自动同步到state。
  • 如果需要把页面上数据的变化,同步到state中,需要手动添加onChange事件,拿到最新的数据,并且调用this.setState( { } )将数据及时同步到state,以这种方式实现react的数据的双向流动。
  • Vue中为页面上的元素提供了ref属性,所以在Vue中可以使用this.$refs.xxx 来获取页面的元素引用。
  • React中也有ref,在React中通过this.refs.xxx来获取页面元素的引用。
    如下:
import React from 'react'

export default class BindEventThree extends React.Component{
    constructor(){
        super();
        this.state = {
            message:'哈哈哈哈哈',
            name:'tom'
        }
    }
    render(){
        return 

{this.state.message}

{/* react中当为input绑定value值后,必须要做的事情,要么为input 添加readOnly属性,要么为input添加onChange处理事件 */} {/* */} {this.textChange(e)}} ref='txt'/>
} //每当文本框的内容变化,自然会调用该事件 textChange=(e)=>{ //onChange事件中用于获取文本框的值有两种方案 //方案1、通过参数e来获取 //console.log(e.target.value); //方案2、通过refs来获取 //console.log(this.refs.txt.value) const newValues = e.target.value; this.setState({ message:newValues }) } changeState=()=>{ this.setState({ message:'啦啦啦啦啦啦' }) } }

14、React的生命周期

  • 先对Vue的生命周期有一个基本的了解


    react从0到1的探索记录02_第2张图片
    Vue的生命周期图解
  • React的生命周期
    生命周期的概念:每个组件的实例,从 创建、到运行、直到销毁,在这个过程中,会出发一些列 事件,这些事件就叫做组件的生命周期函数;

React组件生命周期分为三部分:

  • 组件创建阶段:特点:一辈子只执行一次

componentWillMount: render: componentDidMount:

  • 组件运行阶段:按需,根据 props 属性 或 state 状态的改变,有选择性的 执行 0 到多次

componentWillReceiveProps: shouldComponentUpdate: componentWillUpdate: render: componentDidUpdate:

  • 组件销毁阶段:一辈子只执行一次
react从0到1的探索记录02_第3张图片
React生命周期图解

React生命周期各部分的详解

  • React各阶段生命周期回调函数概括总结如下表


    react从0到1的探索记录02_第4张图片
    React各阶段生命周期回调函数概括总结
  • 组件生命周期的执行顺序
Mounting(组件创建阶段)

constructor();
componentWillMount();
render();
componentDidMount();

Updating(组件运行阶段)

componentWillReceiveProps(nextProps)
shouldComponentUpdate(nextProps,nextState)
componentWillUpdate((nextProps,nextState)
render()
componentDidUpdate(prevProps,prevState)

Unmounting(组件卸载或者销毁阶段)

componentWillUnmount();

关于defaultProps

创建组件之前,会先初始化默认的props属性,在全局调用一次,严格意义上来讲,这并不是组件生命周期的一部分。在组件创建并且加载的时候,首先调用constructor构造器中的this.state={},来初始化组件的状态。

defaultProps的使用
  • 在组件中通过static defaultProps来给组件的 props 提供默认值。
  • 设置默认属性值之后,如果外界没有传递相关参数,那么设置的该属性值在组件初始化的时候就会派上用场,当有相关参数传递的时候,那么外界传递的参数就会替代该设置的默认值。
propTypes的使用
  • 在组件中通过propTypes给组件的 props 进行类型校验。
  • 封装组件的目的是为了方便高效的开发,在封装组件的时候通常会为组件的一些必要数据进行校验,保证传递的参数是符合要求的,如果不符合要求,就在控制台给出警告。
  • React中通常会使用static propTypes对象对于外界传递的参数做类型校验,在React15的版本之前,prop-types并没有从React中抽离出来,在15的版本之后,才从React中抽离了出来,作为单独的一部分。
    也就是说,在React15的版本之前,不需要安装该模块,可以直接使用,但是在15版本之后,需要手动安装,才可以使用。 npm install prop-types 安装prop-types。

CounterTwo.jsx组件如下:

import React from 'react'
//导入参数传递校验的模块
import dataRules from 'prop-types'

export default class CounterTwo extends React.Component{
    constructor(props){
        super(props)
        this.state = {}
    }
    //在封装一些组件的时候,组件内部肯定有一些数据是必须的,哪怕用户并没有传递一些相关的启动参数,这个时候在组件的内部,尽量给自己提供一个默认值
    //在组件中通过static defaultProps来为组件设置默认属性值
    static defaultProps = {
        oneCount:10
        //设置默认属性值之后,如果外界没有传递相关参数,那么设置的该属性值在组件初始化的时候就会派上用场,当有相关参数传递的时候,那么外界传递的参数就会替代该设置的默认值。
    }
    

    //封装组件的目的是为了方便高效的开发,在封装组件的时候通常会为组件的一些必要数据进行校验,保证传递的参数是符合要求的,如果不符合要求,就在控制台给出警告。

    //React中通常会使用static propTypes对象对于外界传递的参数做类型校验,在React15的版本之前,prop-types并没有从React中抽离出来,在15的版本之后,才从React中抽离了出来,作为单独的一部分。
    //也就是说,在React15的版本之前,不需要安装该模块,可以直接使用,但是在15版本之后,需要手动安装,才可以使用。 npm install prop-types
    static propTypes = {
        //定义该组件传递的参数类型为number类型
        oneCount:dataRules.number
    }
    render(){
        return 

这是一个Counter计数器组件


当前的数量是{this.props.oneCount}

} }

index.js

// console.log("React真好用")
import React from 'react'
import ReactDom from 'react-dom'

import CounterTwo from '@/components/CounterTwo'


ReactDom.render(
{/* 在这里规定每个使用该组件的用户必须传递一个默认的数量值,作为组件初始化的数据 */}
,document.getElementById('app'))

你可能感兴趣的:(react从0到1的探索记录02)