this的绑定问题
return (
<div>
//相当于 foo = fn,
//无法确定this,又因为是类,而且babel编译会开启严格模式
//this = undefined
<button onClick={this.btn1Click}>按钮1</button>
</div>
)
如何解决this的问题呢?
- bind给btnClick显示绑定this
- 使用 ES6 class fields 语法
- 事件监听时传入箭头函数(个人推荐)
在 JavaScript 中,普通函数的 this 是在函数被调用时根据调用方式动态确定的,可以通过函数调用、方法调用、构造函数调用等方式来改变 this 的指向。
然而,箭头函数的 this 绑定与普通函数不同。箭头函数没有自己的 this 绑定,它会继承外层作用域的 this 值,也就是定义箭头函数时的上下文。
在类组件中,当箭头函数作为类属性中的方法时,它继承了类的实例作为上下文。这意味着箭头函数的 this 指向的是组件实例,而不是调用箭头函数的对象。
因此,当你将箭头函数作为按钮的点击事件处理程序时,它会继承按钮所在的上下文,也就是组件实例。这样,在箭头函数内部,你可以通过 this 来访问组件实例的属性和方法。
/*
this的四种绑定规则:
1.默认绑定 独立执行 foo()
2.隐式绑定 被一个对象执行 obj.foo() -> obj
3.显式绑定: call/apply/bind foo.call("aaa") -> String("aaa")
4.new绑定: new Foo() -> 创建一个新对象, 并且赋值给this
*/
class App extends React.Component {
// class fields
name = "App"
constructor() {
super()
this.state = {
message: "Hello World",
counter: 100
}
this.btn1Click = this.btn1Click.bind(this)
}
btn1Click() {
console.log("btn1Click", this);
this.setState({ counter: this.state.counter + 1 })
}
btn2Click = () => {
console.log("btn2Click", this)
this.setState({ counter: 1000 })
}
btn3Click() {
console.log("btn3Click", this);
this.setState({ counter: 9999 })
}
render() {
const { message } = this.state
return (
<div>
{/* 1.this绑定方式一: bind绑定
即为 this.btn1Click = this.btn1Click.bind(this) */}
<button onClick={this.btn1Click}>按钮1</button>
{/* 2.this绑定方式二: ES6 class fields
即为 箭头函数会沿着作用域链寻找this*/}
<button onClick={this.btn2Click}>按钮2</button>
{/* 3.this绑定方式三: 直接传入一个箭头函数(重要、常用) */}
<button onClick={() => this.btn3Click()}>按钮3</button>
<h2>当前计数: {this.state.counter}</h2>
</div>
)
}
}
事件参数传递
一、获取event对象
- 拿到event对象来做一些事情(比如阻止默认行为)
- 那么默认情况下,event对象有被直接传入,函数就可以获取到event对象;
render() {
const { message } = this.state
return (
<div>
{/* 1.event参数的传递 */}
<button onClick={this.btnClick.bind(this)}>按钮1</button>
<button onClick={(event) => this.btnClick(event)}>按钮2</button>
</div>
)
}
btnClick(event, name, age) {
console.log("btnClick:", event, this)
}
二、获取更多参数
- 有更多参数时,我们最好的方式就是传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数;
render() {
const { message } = this.state
return (
<div>
{/* 2.额外的参数传递 */}
<button onClick={this.btnClick.bind(this, "kobe", 30)}>按钮3(不推荐)</button>
<button onClick={(event) => this.btnClick(event, "why", 18)}>按钮4</button>
</div>
)
}
btnClick(event, name, age) {
console.log("btnClick:", event, this)
console.log("name, age:", name, age)
}
React条件渲染
- 条件判断语句
- 适合逻辑较多的情况
- 三元运算符
- 适合逻辑比较简单
- 与运算符&&
- 适合如果条件成立,渲染某一个组件;如果条件不成立,什么内容也不渲染;
- v-show的效果
- 主要是控制display属性是否为none
// 1.条件判断方式一: 使用if进行条件判断
let showElement = null
if (isReady) {
showElement = <h2>准备开始比赛吧</h2>
} else {
showElement = <h1>请提前做好准备!</h1>
}
return (
<div>
{/* 1.方式一: 根据条件给变量赋值不同的内容 */}
<div>{showElement}</div>
{/* 2.方式二: 三元运算符 isReady:boolean */}
<div>{ isReady ? <button>开始战斗!</button>: <h3>赶紧准备</h3> }</div>
{/* 3.方式三: &&逻辑与运算 */}
{/* 场景: 当某一个值, 有可能为undefined时, 使用&&进行条件判断 */}
<div>{ friend && <div>{friend.name + " " + friend.desc}</div> }</div>
{/* 4.v-show的效果 display:boolean */}
<h2 style={{display: isShow ? 'block': 'none'}}>哈哈哈哈</h2>
</div>
)
}
JSX的本质
jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖。 所有的jsx最终都会被转换成React.createElement的函数调用。
createElement需要传递三个参数:
- 参数一:type
- 当前ReactElement的类型;
- 如果是标签元素,那么就使用字符串表示 “div”;
- 如果是组件元素,那么就直接使用组件的名称;
- 参数二:config
- 所有jsx中的属性都在config中以对象的属性和值的形式存储;
- 比如传入className作为元素的class;
- 参数三:children
- 存放在标签中的内容,以children数组的方式进行存储;
- 当然,如果是多个元素呢?React内部有对它们进行处理,处理的源码在下方
render() {
const { message } = this.state
return (
<div>
<div className="header">Header</div>
<div className="Content">
<div>{message}</div>
<ul>
<li>列表数据1</li>
<li>列表数据2</li>
<li>列表数据3</li>
<li>列表数据4</li>
<li>列表数据5</li>
</ul>
</div>
<div className="footer">Footer</div>
</div>
)
}
编译后
render() {
const { message } = this.state
const element = React.createElement(
"div",
null,
/*#__PURE__*/ React.createElement(
"div",
{
className: "header"
},
"Header"
),
/*#__PURE__*/ React.createElement(
"div",
{
className: "Content"
},
/*#__PURE__*/ React.createElement("div", null, "Banner"),
/*#__PURE__*/ React.createElement(
"ul",
null,
/*#__PURE__*/ React.createElement(
"li",
null,
"\u5217\u8868\u6570\u636E1"
),
/*#__PURE__*/ React.createElement(
"li",
null,
"\u5217\u8868\u6570\u636E2"
),
/*#__PURE__*/ React.createElement(
"li",
null,
"\u5217\u8868\u6570\u636E3"
),
/*#__PURE__*/ React.createElement(
"li",
null,
"\u5217\u8868\u6570\u636E4"
),
/*#__PURE__*/ React.createElement("li", null, "\u5217\u8868\u6570\u636E5")
)
),
/*#__PURE__*/ React.createElement(
"div",
{
className: "footer"
},
"Footer"
)
);
console.log(element)
return element
}
jsx是通过babel帮我们进行语法转换的,所以我们之前写的jsx代码都需要依赖babel。 babeljs.io/repl/#?pres…
虚拟DOM的创建过程
-
通过 React.createElement 最终创建出来一个 ReactElement对象:
- React利用ReactElement对象组成了一个JavaScript的对象树:
- JavaScript的对象树就是虚拟DOM(Virtual DOM);
- 将之前的jsx返回结果进行打印
-
jsx – 虚拟DOM – 真实DOM