当前位置: 首页 > article >正文

React(二):JSX语法解析+综合案例

事件绑定

this绑定方式

问题:在事件执行后,需获取当前类的对象中相关属性,此时需要this——当打印时,发现this为undefined,这又是为啥?

假设有一个btnClick函数,但它并不是我们主动调用的,而是当button发生改变时,React内部调用→内部调用时,并不知道要如何绑定正确的this

解决办法:

  1. bind给btnClick显示绑定this
  2. 使用 ES6 class fields 语法
  3. 事件监听时传入箭头函数(较为推荐)
<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    /* 
    this的四种绑定规则 
     1.默认绑定:独立执行foo()
     2.隐式绑定:被一个对象执行obj.foo() ->obj
     3.显示绑定:call/apply/bind  foo.call('aaa') ->String('aaa')
     4.new绑定:new Foo() -> 创建一个新对象,并赋值给this
    */
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          count:100
        }
      }

      btn1Click() {
        this.setState({ 
          count:this.state.count+1
        })
      }

      // 箭头函数无this,只能去上一层找
      btn2Click = () => {
        this.setState({ 
          count:this.state.count-1
        })
      }

      btn3Click() {
        this.setState({ 
          count:this.state.count-1
        })
      }

      render(){
        const {count} = this.state
        return (
          <div>
            <h1>{ count }</h1>
            {/* 1.this绑定方式一:bind绑定 */}
            <button onClick={this.btn1Click.bind(this)}>按钮1</button>

            {/* 2.this绑定方式二:箭头函数ES6 class fields */}
            <button onClick={this.btn2Click}>按钮2</button>

            {/* 3.this绑定方式三:直接传入一个箭头函数 */}
            <button onClick={() => this.btn3Click()}>按钮3</button>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>
事件参数传递

1.获取默认参数:即event对象

2.获取更多参数:可通过传入一个箭头函数,主动执行的事件函数,并且传入相关的其他参数

<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          message:"Hello World"
        }
      }

      btnClick (event,name,age) {
        console.log("点击事件", event,this);
        console.log("name:", name, "age:",age);
      }

      render(){
        const {message} = this.state
        return (
          <div>
            {/* 1.event参数的传递 */}
            <button onClick={this.btnClick}>按钮1</button>
            <button onClick={(event) => this.btnClick(event)}>按钮2</button>

            {/* 2.传递额外的参数 */}
            <button onClick={(event) => this.btnClick(event, "why", 30)}>按钮3</button>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>

条件渲染

在vue中,我们会通过指令来控制:比如v-if、v-show;

在React中,所有的条件判断都和普通的JavaScript代码一致;

常见条件渲染方式:

1.条件判断语句

2.三元运算符

3.与运算符&&

<body>
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script type="text/babel">
    //1.创建root
    const root = ReactDOM.createRoot(document.getElementById('root'))

    //2..定义App根组件
    class App extends React.Component {
      constructor() {
        super()

        this.state = {
          isReady:true,

          friend:{
            name:"lucy",
            age:22,
            gender:"女"
          }
        }
      }

      render(){
        const {isReady,friend} = this.state
        // 1.条件判断方式一:使用if进行条件判断
        let showElement = null
        if(isReady) {
          showElement = <h2>准备开始比赛吧</h2>
        }else{
          showElement = <h1>我还没有准备好嘞</h1>
        }
        return (
          <div>
            {/* 方式一:根据条件给变量赋值不同的内容 */}
            <div>{ showElement }</div>

            {/* 方式二:三元运算符 */}
            <div>{isReady? <button>准备开始</button> : <button>还没有准备好</button> }</div>

            {/* 方式三:&&运算符 */}
            {/* 场景:当某一个值,有可能为undefined时,使用&&进行条件判断 */}
            <div>{ friend && <div>{friend.name + friend.age + friend.gender}</div> }</div>
          </div>
        )
      }
    }

    // 3.将App组件渲染到root上
    root.render(<App />)
  </script>
</body>

实现v-show的效果:

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      message:"Hello World",
      isShow:true
    }
  }

  ediClick() {
    this.setState({
      isShow:!this.state.isShow
    })
  }
  render(){
    const {message,isShow} = this.state
    return (
      <div>
        <button onClick={this.ediClick.bind(this)}>切换1</button>
        <h1 >{ isShow? message : "" }</h1>

        {/* v-show的效果 */}
        <button onClick={this.ediClick.bind(this)}>切换2</button>
        <h1 style={{display:isShow ? "block" : "none"}}>{ message }</h1>
      </div>
    )
  }
}

列表渲染

class App extends React.Component {
  constructor() {
    super()

    this.state = {
      students:[
        {id:1, name:'Jack', age:18},
        {id:2, name:'Tom', age:20},
        {id:3, name:'Lucy', age:22},
        {id:4, name:'Lily', age:24}
      ]
    }
  }

  render(){
    const {students} = this.state

    // 展示年龄大于20的
    const filterStudents = students.filter(item => item.age >= 20)
    return (
      <div>
        <h2>学生信息列表</h2>
        <div className="list">
          {/* 绑定唯一标识key:提高diff算法时的效率 */}
          {filterStudents.map(item => 
            <div key={item.id} className="item">
              <p>id:{item.id}</p>
              <p>姓名:{item.name}</p>
              <p>年龄:{item.age}</p>
            </div>
          )}
        </div>
      </div>
    )
  }
}

原理本质

babel转换

实际上,jsx 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖→所有的jsx最终都会被转换成React.createElement的函数调用

createElement需要传递三个参数:

1.参数一:type

  • 当前ReactElement的类型;
  • 如果是标签元素,那么就使用字符串表示 “div”;
  • 如果是组件元素,那么就直接使用组件的名称;

2.参数二:config

  • 所有jsx中的属性都在config中以对象的属性和值的形式存储;
  • 比如传入className作为元素的class;

3.参数三:children

  • 存放在标签中的内容,以children数组的方式进行存储;

直接编写jsx代码:

<div>
  <div className="header">header</div>
  <div className="Content">
    <div>Banner</div>
    <ul>
      <li>数据列表1</li>
      <li>数据列表2</li>
      <li>数据列表3</li>
    </ul>
  </div>
  <div className="footer">footer</div>
</div>

经过babel转译后:

React.createElement(
'div',
null,
React.createElement('div', { className: 'header' }, 'header'),
React.createElement(
  'div',
  { className: 'Content' },
  React.createElement('div', null, 'Banner'),
  React.createElement(
    'ul',
    null,
    React.createElement('li', null, '数据列表1'),
    React.createElement('li', null, '数据列表2'),
    React.createElement('li', null, '数据列表3')
  )
),
React.createElement('div', { className: 'footer' }, 'footer')
);
虚拟DOM生成

通过React.createElement最终创建出一个ReactElement对象→它组成了一个JS对象树→即虚拟DOM

阶段案例-购物车

<body>
  
  <div id="root"></div>

  <script src="../lib/react.js"></script>
  <script src="../lib/react-dom.js"></script>
  <script src="../lib/babel.js"></script>

  <script src="./data.js"></script>
  <script src="./format.js"></script>

  <script type="text/babel">
    // 1.定义App根组件
    class App extends React.Component {
      constructor() {
        super()
        this.state = {
          books: books
        }
      }

      getTotalPrice() {
        const totalPrice = this.state.books.reduce((preValue, item) => {
          return preValue + item.count * item.price
        }, 0)
        return totalPrice
      }

      changeCount(index, count) {
        const newBooks = [...this.state.books]
        newBooks[index].count += count
        this.setState({ books: newBooks })
      }

      removeItem(index) {
        const newBooks = [...this.state.books]
        newBooks.splice(index, 1)
        this.setState({ books: newBooks })
      }

      renderBookList() {
        const { books } = this.state

        return <div>
          <table>
            <thead>
              <tr>
                <th>序号</th>
                <th>书籍名称</th>
                <th>出版日期</th>
                <th>价格</th>
                <th>购买数量</th>
                <th>操作</th>
              </tr>
            </thead>
            <tbody>
              {
                books.map((item, index) => {
                  return (
                    <tr key={item.id}>
                      <td>{index + 1}</td>
                      <td>{item.name}</td>
                      <td>{item.date}</td>
                      <td>{formatPrice(item.price)}</td>
                      <td>
                        <button 
                          disabled={item.count <= 1}
                          onClick={() => this.changeCount(index, -1)}
                        >
                          -
                        </button>
                        {item.count}
                        <button onClick={() => this.changeCount(index, 1)}>+</button>
                      </td>
                      <td><button onClick={() => this.removeItem(index)}>删除</button></td>
                    </tr>
                  )
                })
              }
            </tbody>
          </table>
          <h2>总价格: {formatPrice(this.getTotalPrice())}</h2>
        </div>
      }

      renderBookEmpty() {
        return <div><h2>购物车为空, 请添加书籍~</h2></div>
      }

      render() {
        const { books } = this.state
        return books.length ? this.renderBookList(): this.renderBookEmpty()
      }
    }

    // 2.创建root并且渲染App组件
    const root = ReactDOM.createRoot(document.querySelector("#root"))
    root.render(<App/>)
  </script>

</body>

format.js(数值格式化文件)

function formatPrice(price) {
  return "¥" + Number(price).toFixed(2)
}

data.js(数据文件) 

const books = [
  {
    id: 1,
    name: '《算法导论》',
    date: '2006-9',
    price: 85.00,
    count: 1
  },
  {
    id: 2,
    name: '《UNIX编程艺术》',
    date: '2006-2',
    price: 59.00,
    count: 1
  },
  {
    id: 3,
    name: '《编程珠玑》',
    date: '2008-10',
    price: 39.00,
    count: 1
  },
  {
    id: 4,
    name: '《代码大全》',
    date: '2006-3',
    price: 128.00,
    count: 1
  },
]

http://www.kler.cn/a/588303.html

相关文章:

  • 单片机自学指南
  • Java 绘制图形验证码
  • 【数据库相关】mysql数据库巡检
  • Adobe Premiere Pro的简单音频调节
  • 介绍如何使用YOLOv8模型进行基于深度学习的吸烟行为检测
  • Java集合简单理解
  • 快速导出接口设计表——基于DOMParser的Swagger接口详情半自动化提取方法
  • 物联网(Internet of Things,IoT)的核心概念
  • 【机器学习】主成分分析法求数据前n个主成分
  • 基于javaweb的SpringBoot精美物流管理系统设计与实现(源码+文档+部署讲解)
  • 地基Prompt提示常用方式
  • DQN 玩 2048 实战|第二期!设计 ε 贪心策略神经网络,简单训练一下吧!
  • 【SegRNN 源码理解】验证集和测试集
  • 【C语言】函数和数组实践与应用:开发简单的扫雷游戏
  • 【Linux文件IO】系统IO中API描述和基本使用
  • MQTT客户端调试工具模拟MQTT设备接入物联网平台
  • 使用OpenCV与Python编写自己的俄罗斯方块小游戏
  • Java 中 String、StringBuffer 、StringBuffer正确使用方式
  • Java实现【将Markdown格式文本转换为纯文本】
  • 2021 年 12 月青少年软编等考 C 语言六级真题解析