JSX的基本使用(二)

108 阅读4分钟

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条件渲染

  1. 条件判断语句
    • 适合逻辑较多的情况
  2. 三元运算符
    • 适合逻辑比较简单
  3. 与运算符&&
    • 适合如果条件成立,渲染某一个组件;如果条件不成立,什么内容也不渲染;
  4. 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需要传递三个参数:

  1. 参数一:type
    • 当前ReactElement的类型;
    • 如果是标签元素,那么就使用字符串表示 “div”;
    • 如果是组件元素,那么就直接使用组件的名称;
  2. 参数二:config
    • 所有jsx中的属性都在config中以对象的属性和值的形式存储;
    • 比如传入className作为元素的class;
  3. 参数三: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的创建过程

  1. 通过 React.createElement 最终创建出来一个 ReactElement对象:

    • React利用ReactElement对象组成了一个JavaScript的对象树:
    • JavaScript的对象树就是虚拟DOM(Virtual DOM);
    • 将之前的jsx返回结果进行打印 image.png
  2. jsx – 虚拟DOM – 真实DOM image.png