概述
写在前面
在最近看了React之后,一直觉得学的懵懵然,虽然很多大佬的手写笔记,写的都很不错,但是我一直没有我想要的那种细无巨细,比如类式组件this指向问题的追根溯源,又比如三大实例属性简写的由来,总之我还是决定做一份事无巨细的笔记。
那就让我们开始吧!
复习类相关的知识
创建实例对象
//创建一个Person类
class Person {
}
let person1 = new Person();
console.log(person1)
- 输出分解
红色框代表new出来的实例对象
蓝色框代表这个实例对象是由Person这个类new出来的。
目的:为了区别实例是由哪个类new出来的
接收参数
- 使用构造器方法(可以不写)
构造器也是在原型上的
//创建一个Person类
class Person {
//构造器方法
constructor(name,age){
//构造器中的this是谁?—— 类的实例对象
this.name = name
this.age = age
}
}
注意: 构造器中的this是谁?—— 类的实例对象
- 定义方法
//创建一个Person类
class Person {
//构造器方法
constructor(name,age){
//构造器中的this是谁?—— 类的实例对象
this.name = name
this.age = age
}
//一般方法
speak(){
//speak方法放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我年龄是${this.age}`);
}
}
注意:
speak方法放在了哪里?——类的原型对象上,供实例使用
通过Person实例调用speak时,speak中的this就是Person实例
- 继承
书写构造器之后必须书写super、必须放在带有使用this关键字的前面
super:调用父类的构造器
//创建一个Student类,继承于Person类
class Student extends Person {
constructor(name,age,grade){
super(name,age)
this.grade = grade
this.school = '尚硅谷'
}
//重写从父类继承过来的方法
speak(){
console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);
this.study()
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习');
}
}
- 调用方法
如果不重写方法,那么就会调用父类提供的方法,这个方法会通过原型链在person实例的原型对象上找到。
class Student extends Person {
constructor(name,age,grade){
super(name,age)
this.grade = grade
this.school = '尚硅谷'
}
}
- 重写方法
//创建一个Student类,继承于Person类
class Student extends Person {
constructor(name,age,grade){
super(name,age)
this.grade = grade
this.school = '尚硅谷'
}
//重写从父类继承过来的方法
speak(){
console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);
this.study()
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习');
}
}
蓝色框的方法在student实例的原型对象上、红色框的方法在person实例的原型对象上。
调用方法采用就近原则,通过原型链调用最先找到的那个方法。
-总结:
1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。
第11集 类式组件
类名或者函数名就是组件名
创建类式组件
- 必须继承React内置一个类
必须继承React.Component
- 可以省略构造器
传送门
https://react.docschina.org/
- 书写必备的三个条件
- 必须继承React.Component
- 必学书写render方法
- redner必须有返回值
<script type="text/babel">
//1.创建类式组件
class MyComponent extends React.Component {
render(){
//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
- render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
-
执行了ReactDOM.render(…之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。 2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。 3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
-
render中的this是谁?
MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
第12集 对state的理解
简单组件、复杂组件
有无“状态”,有就是复杂组件、无就是简单组件
组件实例的三大核心属性
state、prrops、refs
第13集 初始化state
组件三大核心属性:state
- 向state属性传值(书写构造器)
1、构造器传值:接受props
传送门
https://react.docschina.org/
2、必须调用super
super(props)
如果书写构造器不调用就会报错
- 给state赋值是一个对象
//初始化状态
this.state = {isHot:false,wind:'微风'}
- 渲染到页面
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
constructor(props){
super(props)
//初始化状态
this.state = {isHot:false}
}
render(){
return <h1 今天天气很{isHot ? '炎热' : '凉爽'}</h1>
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
第14集 react中事件绑定
原生事件的绑定
- 3种类型
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button onclick="demo()">按钮3</button>
</body>
<script type="text/javascript" >
const btn1 = document.getElementById('btn1')
btn1.addEventListener('click',()=>{
alert('按钮1被点击了')
})
const btn2 = document.getElementById('btn2')
btn2.onclick = ()=>{
alert('按钮2被点击了')
}
function demo(){
alert('按钮3被点击了')
}
</script>
- 实现效果
- 在React依然可以使用原生绑定事件(只要能绑定到render方法返回的标签就行)
实际中不会这样使用
- on类api得驼峰命名
1、为onClick赋值一个方法必须使用{} 并且不能带()。
必须使用{}原因:
使用{},是因为这里还是将函数赋值给onClick,不然会被解析为字符串。简单来说就是这里要使用js表达式了。
不能带()原因:这里就为了函数赋值给onClick回调,而不是将函数的返回值传递给onClick来回调
不然一渲染就会直接调用这个函数。而且onClick会回调函数的返回值,而不是函数本身。
第15集 类中方法的this
- babel开启严格模式
this是undefined
-
在render中的this就是组件实例对象,因为是组件实例对象调用的redner方法。
-
使用外作用域定义变量取到组件实例对象的this
- 将函数方法书写到类式组件中
- onClick不能直接调用方法(组件实例对象调用-添加this)
但是这里changeWeather方法中的this指向还是undefined
类中方法的this指向
<script type="text/javascript" >
class Person {
constructor(name,age){
this.name = name
this.age = age
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用study时,study中的this就是Person实例
console.log(this);
}
}
const p1 = new Person('tom',18)
p1.study() //通过实例调用study方法
const x = p1.study
x() // 直接调用study
</script>
-
类中定义的所有方法,在局部作用域都开启了严格模式
-
函数中开启严格模式
- onClick是直接回调这个函数(不是组件实例对象调用的)
- 直接强行new一个类式组件的实例对象
这里的this指向就是组件实例对象
-
由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
-
类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
<script type="text/babel">
//1.创建组件
class Weather extends React.Component{
//构造器调用几次? ———— 1次
constructor(props){
console.log('constructor');
super(props)
//初始化状态
this.state = {isHot:false,wind:'微风'}
//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
}
//render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
render(){
console.log('render');
//读取状态
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//changeWeather调用几次? ———— 点几次调几次
changeWeather(){
//changeWeather放在哪里? ———— Weather的原型对象上,供实例使用
console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);
//严重注意:状态(state)不可直接更改,下面这行就是直接更改!!!
//this.state.isHot = !isHot //这是错误的写法
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
第16集解决类中this指向问题
使用bind
bind : 生成新函数、改变this指向
//解决changeWeather中this指向问题
this.changeWeather = this.changeWeather.bind(this)
解析过程:在组件对象的原型上找到函数,使用bind创建了一个一模一样的函数,但是讲函数的this修改为组件实例对象。并且将这个新函数作为一个值,赋值给了实例对象的一个叫changeWeather的方法。这样实例对象自身就会有一个changeWeather的方法。
注意:左边的changeWeather 在 实例对象身上、右边的changeWeather是原型对象上的。这段代码核心就是将原型对象上的方法加工改变this添加的实例对象上。
第17集 对setState的使用
- 对state对象的值修改必须使用setSate内置api(在React.component)
console.log('changeWeather');
//获取原来的isHot值
const isHot = this.state.isHot
//严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
this.setState({isHot:!isHot})
console.log(this);
- 修改对象值是局部修改
严重注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。
- 调用次数
构造器调用几次? ———— 1次(创建实现对象时调用)
render调用几次? ———— 1+n次 1是初始化的那次 n是状态更新的次数
changeWeather调用几次? ———— 点几次调几次
第18集 state的简写方式
核心解决手段来源:类中可以直接写赋值语句
class Car {
constructor(name,price){
this.name = name
this.price = price
// this.wheel = 4
}
//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
a = 1
wheel = 4
static demo = 100
}
const c1 = new Car('奔驰c63',199)
const s1 = new Student('1','2');
简写方法
- 由于自定义函数太多了,大量使用bind。
将函数作为一个值直接赋值到一个属性上。
注意: 还是会报错
解决方法,将function改为箭头函数模式
//自定义方法————要用赋值语句的形式+箭头函数
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
原因:在箭头函数中,this引用的是定义箭头函数的上下文(红宝书p300)
- 注意不允许这么写
changeWeather()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
简写state
直接使用赋值语句
//初始化状态
state = {isHot:false,wind:'微风'}
第19集总结state
1. state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
2. 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
第20集 props的基本使用
传递组件属性
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
// console.log(this);
const {name,age,sex} = this.props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry" age={19} sex="男"/>,document.getElementById('test1'))
ReactDOM.render(<Person name="tom" age={18} sex="女"/>,document.getElementById('test2'))
const p = {name:'老刘',age:18,sex:'女'}
// console.log('@',...p);
// ReactDOM.render(<Person name={p.name} age={p.age} sex={p.sex}/>,document.getElementById('test3'))
ReactDOM.render(<Person {...p}/>,document.getElementById('test3'))
</script>
第21集 批量传递props
展开运算符
传送门
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Spread_syntax
<script type="text/javascript" >
let arr1 = [1,3,5,7,9]
let arr2 = [2,4,6,8,10]
console.log(...arr1); //展开一个数组
let arr3 = [...arr1,...arr2]//连接数组
//在函数中使用
function sum(...numbers){
return numbers.reduce((preValue,currentValue)=>{
return preValue + currentValue
})
}
console.log(sum(1,2,3,4));
//构造字面量对象时使用展开语法
let person = {name:'tom',age:18}
let person2 = {...person}
//console.log(...person); //报错,展开运算符不能展开对象
person.name = 'jerry'
console.log(person2);
console.log(person);
//合并
let person3 = {...person,name:'jack',address:"地球"}
console.log(person3);
</script>
批量传入props
react+babel 可以允许使用展开运算符展开对象。
- 仅用于标签属性的传递
第22集 对props进行限制
对标签属性传递的类型进行限制
- 在组件上添加propTypes属性
在React每次创建组件实例对象的时候就会访问组件本身的propTypes属性以便于限制props
- 不同版本不同写法
//对标签属性进行类型、必要性的限制
Person.propTypes = {
// 15版本
name: React.PropTypes.string,
// 16版本
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
speak:PropTypes.func,//限制speak为函数,不使用function就是为了防止与关键字发生冲突
}
16版本之后
<!-- 引入prop-types,用于对组件标签属性进行限制 -->
<script type="text/javascript" src="../js/prop-types.js"></script>
引入一个依赖包就产生一个全局对象,这里会产生一个propTypes全局对象。
属性默认值
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
第23集 props的简写方式
props是只读的
简写props
- 将类似限制、默认值书写到类式组件内部
在类的原型上添加属性(使用static关键字)
第24集 类式组件中的构造器与props
- 构造器传送门
https://zh-hans.reactjs.org/docs/react-component.html#constructor
-实际使用
类中的构造器的作用
- 如果不使用构造器接受props和使用super接受props,就无法使用实例对象访问props
constructor(props){
//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
// console.log(props);
super(props)
console.log('constructor',this.props); // super constructor里面缺一个没传props参数都不可,否则就是undefined
}
第25集 函数式组件使用props
函数式组件没有实例对象,但是可以接受参数
<script type="text/babel">
//创建组件
function Person (props){
const {name,age,sex} = props
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age}</li>
</ul>
)
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
</script>
对props进行限制
- 对组件添加属性
Person.propTypes = {
name:PropTypes.string.isRequired, //限制name必传,且为字符串
sex:PropTypes.string,//限制sex为字符串
age:PropTypes.number,//限制age为数值
}
//指定默认标签属性值
Person.defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
第26集 props总结
- 理解
1. 每个组件对象都会有props(properties的简写)属性
2. 组件标签的所有属性都保存在props中
- propsTypes
propsTypes是React要求的属性名,这个属性用来保存一个对象进而对props进行限制。
PropsTypes是使用prop-types库进限制(需要引入prop-types库)产生的全局对象
第27集 字符串形式的ref
- 使用原生id属性事件绑定
- 使用ref标识
<input ref="input1" type="text" placeholder="点击按钮提示数据"/>
//展示左侧输入框的数据
showData = ()=>{
const {input1} = this.refs
console.log(input1.value)
}
第28集 回调形式的ref
过时APl:String类型的Refs
传送门
https://zh-hans.reactjs.org/docs/refs-and-the-dom.html
- 回调形式的ref
<input ref={c => this.input1 = c } type="text" placeholder="点击按钮提示数据"/>
回调的箭头函数接收的参数正好就是ref属性所在的标签
- 上述代码的执行过程
在创建实例对象之后,实例对象调用render方法直接回调箭头函数。将作为参数的标签本身赋值到实例对象上的一个属性上。
这里就是将input标签赋值给实例对象的input属性上。
第29集 回调ref中调用次数的问题
传送门
https://zh-hans.reactjs.org/docs/refs-and-the-dom.html
- 第一次初始化渲染页面调用render
回调ref中调用1次
- 更新过程
回调ref中调用2次本质:
1.初始化调用的回调函数已经被释放,状态更新后再次调用这个方法时就是一个新的方法。
2.由于不确定之前的函数接受到了什么,做了什么动作,为此就传入了null进行第一次调用。
3.在调用第二次的时候就传入了当前节点。
- 实现结果
- jsx注释方法
{/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
- 将 ref 的回调函数定义成 class 的绑定函数的方式
<script type="text/babel">
//创建组件
class Demo extends React.Component{
state = {isHot:false}
showInfo = ()=>{
const {input1} = this
alert(input1.value)
}
changeWeather = ()=>{
//获取原来的状态
const {isHot} = this.state
//更新状态
this.setState({isHot:!isHot})
}
saveInput = (c)=>{
this.input1 = c;
console.log('@',c);
}
render(){
const {isHot} = this.state
return(
<div>
<h2>今天天气很{isHot ? '炎热':'凉爽'}</h2>
{/*<input ref={(c)=>{this.input1 = c;console.log('@',c);}} type="text"/><br/><br/>*/}
<input ref={this.saveInput} type="text"/><br/><br/>
<button onClick={this.showInfo}>点我提示输入的数据</button>
<button onClick={this.changeWeather}>点我切换天气</button>
</div>
)
}
}
//渲染组件到页面
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
第31集 createRef的使用
创建一个专属容器
- 这里的myRef是一个对象,里面的current属性保存的是ref属性所在的标签
第31集 总结 refs
- 一共有4种方式使用refs
第32集 React中的事件处理
1. 通过onXxx属性指定事件处理函数(注意大小写)
1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件---为了更好的兼容性
2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)---为了更高效
2. 通过event.target得到发生事件的DOM元素对象 — 避免过度使用ref
- 事件委托(原理:事件冒泡)
所有的事件都添加到了最外层的标签上
这里就是div
- 避免过度使用ref
发生事件的元素正好就是要操作的元素。就可以使用event.target替代
//展示右侧输入框的数据
showData2 = (event)=>{
alert(event.target.value);
}
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
最后
以上就是可靠小熊猫为你收集整理的React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理写在前面复习类相关的知识第11集 类式组件第12集 对state的理解第13集 初始化state第14集 react中事件绑定第15集 类中方法的this第16集解决类中this指向问题第17集 对setState的使用第18集 state的简写方式第19集总结state第20集 props的基本使用第21集 批量传递props第22集 对props进行限制第23集 pro的全部内容,希望文章能够帮你解决React全家桶:类--类式组件--state属性--事件绑定--类中方法的this--props属性--ref--事件处理写在前面复习类相关的知识第11集 类式组件第12集 对state的理解第13集 初始化state第14集 react中事件绑定第15集 类中方法的this第16集解决类中this指向问题第17集 对setState的使用第18集 state的简写方式第19集总结state第20集 props的基本使用第21集 批量传递props第22集 对props进行限制第23集 pro所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复