可以在谷歌应用商店下载 React Developer Tools,可以更好用
<script type="text/babel">
//1.编写函数式组件
function Demo() {//组件名需要大写,不然 react 会认为标签里面是 html 标签,而不是 react 组件
console.log(this); //此处的 this 是 undefined,因为babel 会在严格模式下翻译代码,严格模式下,函数里的 this 为 undefined
return (
<h1>函数式组件</h1>
)
}
//2.渲染组件到页面
ReactDOM.render(<Demo/>, document.getElementById('test'));
script>
执行ReactDOM.render()之后,发生了什么?
类的基本知识
<script type="text/javascript">
/*
1.类中的构造器不是必须要写的,要对实例进行属性初始化的时候就要写
2.如果 A 类继承了 B 类,且 A 类写了构造器,那么构造器需要在首行调用super()
3.类中所定义的方法,都是放在了类的原型对象上,供实例去使用。
*/
//创建一个类
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}岁了。`)
}
}
const p1 = new Person('Tom', 18)
const p2 = new Person('Jerry', 19)
p1.speak()
p2.speak()
class Student extends Person {
constructor(name, age, grade) {
super(); //必须要调用,否则会报错。调用的好处时,父类拥有的属性赋值就不用写了
// this.name = name;
// this.age = age;
this.grade = grade;
}
//重写父类方法
speak() {
console.log(`我叫${this.name},今年${this.age}岁了,在读${this.grade}。`)
}
}
const s1 = new Student('xiaozhang', 12, '高一');
const s2 = new Student('xiaomei', 13, '高二');
s1.speak()
s2.speak()
script>
DOCTYPE html>
<html>
<head>
<title>React创建类组件title>
head>
<body>
<div id="test">div>
<script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin>script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin>script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js" crossorigin>script>
<script type="text/babel">
//1.创建类式组件
class MyComponent extends React.Component{
render() {
return <h1>React创建类式组件</h1>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('test'))
script>
body>
html>
组件的 render 是放在哪里的?
那组件的实例呢?
执行了 ReactDOM.render()之后,发生了什么?
以下代码借助 state 状态,在按钮每次点击之后,都会改变h1标签的内容
<script type="text/babel">
class MyComponent extends React.Component{
//组件被调用几次,构造器就调用几次
constructor(props) {
super(props);
this.state={isHot:false};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
//setState 的操作是一种合并操作,而不是更新。但是 hooks 的操作好像是合并的
this.setState({isHot:!this.state.isHot});
}
//render被调用了 1+n 次,1 是初始化那次,n 是状态更新的次数
render () {
return <h1 onClick={this.handleClick}>今天的天气很{this.state.isHot?"炎热":"寒冷"}</h1>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
script>
类中的方法默认开启了严格模式,this 是 undefined
this.handleClick = this.handleClick.bind(this)
这行代码是必要的,因为它确保了在组件的方法中使用this
关键字时,this
关键字指向组件实例。
在 Javascript 中,函数的this
关键字指向的是当前执行上下文的对象。在 React 组件中,我们经常需要在组件的方法中使用this
关键字来访问组件的状态或者其他属性和方法。但是,在不进行绑定的情况下,这些方法中的this
关键字指向的是调用该方法的对象,这可能导致代码中的错误或者不可预料的行为。
state 的简写方式
class MyComponent extends React.Component{
//初始化状态
//这样相当于给类增加了一个属性
state = {isHot:true};
//如果这里写成函数表达式,那么 this 将找不到而导致出错
handleClick = () => {
this.setState({isHot:!this.state.isHot});
}
render () {
return <h1 onClick={this.handleClick}>今天的天气很{this.state.isHot?"炎热":"寒冷"}</h1>
}
}
ReactDOM.render(<MyComponent/>, document.getElementById('test'));
强烈注意:
setState
<script type="text/babel">
class Person extends React.Component {
render() {
return (
<ul>
<li>姓名:{this.props.name}</li>
<li>性别:{this.props.gender}</li>
<li>年龄:{this.props.age}</li>
</ul>
)
}
}
//在组件标签中传值,相当于就是往组件的 props 中传值了
ReactDOM.render(<Person name="Tom" gender="男" age="18"/>, document.getElementB-yId('test'));
script>
在组件标签中传值,相当于就是往组件的 props 中传值了
用这样的写法,可以将一个对象的键值对都放在组件的 props 中:
(展开运算符本来不能展开对象的,但是加了花括号后可以用来对象克隆)
(但是在这里,花括号的含义是里面要写 javascript 代码了,只是说 babel+react 语法允许我们使用展开运算符来展开对象,在正常的 javascript 代码中,展开运算符是不能展开对象的,只能与花括号配合来克隆对象)
const p = {name:"小陈", age:18, gender:"男"}
ReactDOM.render(<Person {...p}/>, document.getElementById('test'));
注意,虽然react+babel可以使用展开运算符展开对象,但是也不能随意使用,比如下面这样就不太行。
const p = {name:"小陈", age:18, gender:"男"}
console.log(...p); //这样不行
复制对象时,修改对象属性的时候也可以用
const p = {name:"小陈", age:18, gender:"男"}
const p1 = {...p, name:'小张'}