目录
定义组件
方式一:函数式定义
<script type="text/babel">
//1.创建函数式组件
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
</script>
执行了ReactDOM.render(…之后,发生了什么?
- React解析组件标签,找到了MyComponent组件。
- 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
小结:
- 函数定义组件,函数名必须大写开头
- 函数内部必须有返回值,返回虚拟DOM结构
- render渲染时只能写组件标签,不能只写名字
方式二:类式组件
知识点回顾 --类的基本知识
类创建实例
class Person{
//构造器方法
constructor(name,age){
//构造器中的this是谁?——类的实例对象
this.name = name
this.age = age
//一般方法
speak(){
//speak放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用speak时,speak中的this就指向Person实例
console.log('xxx')
}
}
}
//创建一个实例对象
const p1 = new Person('tom',18)
继承
//创建一个Student类,继承于Person类
class Student extends Person{
constructor(name,age,grade){
super(name,age)
//super调用父类上的属性,必须写在最前面
this.grade = grade
}
//重写从父类继承过来的方法
speak(){
console.log(xxx)
}
}
const s1 = nnew Student('小巡',15,'高一')
小结
1.类中的构造器不是必须写的,要对实例进行一些初始化的操作,如添加指定属性时才写
2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的
3.类中所定义的放大,都是在类的原型对象上,供实例去使用。
类组件定义
//1.创建类式组件
class MyComponent extends React.Component {
render(){
//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
组件实例的三大核心属性 ——state、props、refs
state 组件状态
state在 组件这个类 缔造出来的 实例对象 上
是什么?
- state是组件对象最重要的属性,值是对象(可以包含多个key-value的组合)
- 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)
回顾
原生js绑定事件
<div id="title" onclick="demo()"></div>;
const title = document.getElementById("title");
1.title.onclick = () => {
console.log(xxx);
};
2.title.addEventListener("click", () => {
console.log(xxx);
});
3.function demo() {}
类中的方法this指向
由于类中方法默认开启了局部严格模式,
如果通过实例调用的方法,this指向该实例
如果通过赋值直接调用方法,this指向undefined,如const x = p1.test;x()
怎么用?
//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的原型对象上,供实例使用
//由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
//类中的方法默认开启了局部的严格模式,所以changeWeather中的this为undefined
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"));
state简写方式
//1.创建组件
class Weather extends React.Component{
//初始化状态
state = {isHot:false,wind:'微风'}
render(){
const {isHot,wind} = this.state
return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
}
//自定义方法————要用赋值语句的形式+箭头函数
changeWeather = ()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
}
//2.渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'))
state总结
1.state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
2.组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
注意:
1.组件中render方法中的this为组件实例对象
2.组件自定义的方法中this为undefined,如何解决?
a)强制绑定this: 通过函数对象的bind()
b)赋值语句+箭头函数
3.状态数据,不能直接修改或更新