react基本使用

 事件处理

react事件和DOM事件

react事件原生事件
onClickonclick
onClick={eventListener}οnclick="eventListener()"
e.preventDefalutοnclick="javascript"
class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数
   }
   doSomethind(){

   }
    handleClick(e){
        console.log(e)
        this.doSomethind() //报错,会说找不到这个方法
    }
   render(){
    return (
      <div className='listItem'>
        <span onclick={this.handleClick}>header<span>
      <div>
    )
   }
  }

在面向对象的编程中,this的使用方法会随着引用对象的差别而不同,当被对象引用时指向的是对象,单独函数引用指向的是window,严格模式是undefined,那我们在react中怎么解决这个问题呢?

 this关键词的处理

  • 在jsx中使用bind方法
  • 在构造函数中使用bind方法
  • 使用箭头函数


 

class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数
     // 方法2
     this.handleClick=this.handleClick.bind(this)
   }
   doSomethind(){

   }
    // 方法3,推荐使用,箭头函数的this总是指向定义时的对象,而不是运行时
    handleClick=(e)=>{
        console.log(e)
        this.doSomethind() //报错,会说找不到这个方法
    }
   render(){
    return (
      <div className='listItem'>
        {/*方法1*/}
        <span onclick={this.handleClick.bind(this)}>header<span>   
      <div>
    )
   }
  }

向事件处理程序传递参数

class ListItem extends Component {
     constructor(props){
     super(props) //子类中调用父类构造函数)
     this.state={
         conunt:1
     }
   }
    handleClick(id){
        console.log(id)
    }
   render(){
    return (
      <div className='listItem'>
       {/* 方法1*/}
        <span onclick={this.handleClick.bind(this,1)}>header<span> 
         {/* 方法2*/}
        <span onclick={()=>this.handleClick(1)}>header<span>  
          {/* 传递事件对象event*/}
        <span onclick={(e)=>this.handleClick(1,e)}>header<span>  
      <div>
    )
   }
  }

向父组件传递参数

// 父组件
class App extends Component {
    handDelete(id){
        console.log(id)
    }
    render(){
        <ListItem onDelete={this.handDelete}/>
    }
}
// 子组件
class ListItem extends Component {
     constructor(props){
     super(props)
     this.state={
         conunt:1
     }
   }
   render(){
    return (
      <div className='listItem'>
        <span onclick={()=>this.props.onDelete(this.state.conunt)}>header<span>  
      <div>
    )
   }
  }

React事件机制

DOM事件

在js的事件触发经过3个阶段,事件的捕获->目标对象事件的处理->事件冒泡,假设在text中触发了事件,会经过一个捕获的阶段,父级元素将事件一直传递到本身发生的元素上,在经过本身的事件处理之后,会经历冒泡饿阶段,事件从子元素向父元素冒泡;就因为这样,事件委托成为了可能,就是将子元素的事件处理委托给父元素。

react事件

react会将所有的事件都绑定到document上,而不是某个元素上面,统一的使用事件监听,并在冒泡阶段处理事件,当挂载和卸载组件的时候 只需在统一的事件监听位置,增加或删除对象,因此极大的提高效率;当事件触发的时候,我们的组件会生成一个合成事件,然后传递到documennt中,doucument会通过DispatchEvent回调函数依次执行DispatchEvent中同类型的事件监听函数,事件注册是在组件生成的时候,我们将vDom中所有的事件的原生事件documennt中的一个监听器当中,也就是所有的事件处理函数都存在ListenerBank中 并以key作为索引,这样的好处是将可能要触发的事件分门别类。

react事件要素

  • react事件是合成事件,不是DOM原生事件
  • 在document监听所有支持的事件
  • 使用统一的分发函数dispatchEvent

 认识State

安装react-devtools调试工具

如何定义State

   class ListItem extends Component {
     constructor(props){
     super(props)
     this.state={ //定义一个state
         conunt:1 
     }
   }
   render(){
    return (
      <div className='listItem'>
        <span>{this.state.count}<span>  
      <div>
    )
   }
  } 

 修改State

  • 使用setState
  • setState是异步的
  • State的更新是一个浅合并(shalllow merge)的过程
   class ListItem extends Component {
     constructor(props){
     super(props)
     this.state={
         conunt:1 
     }
   }
   addCunt(){
       console.log('step1',this.state.count)
       this.setState({ //修改一个state
           count:this.state.count+1
       })
       console.log('step2',this.state.count)
   }
   render(){
    return (
      <div className='listItem'>
        <span onclick={()=>this.addCount()}>{this.state.count}<span>  
      <div>
    )
   }
  } 

addCount函数中打印的2次conut的值是一样的,说明setState的处理过程是异步的而不是同步的,react在执行setState时候,优化执行的时机,多个setState合并在一起去执行,如果非要在state变化话后做一些操作的话,其实setState会接收第二个参数。

   class ListItem extends Component {
     constructor(props){
     super(props)
     this.state={
         conunt:1 
     }
   }
   addCunt(){
       this.setState({ //修改一个state
           count:this.state.count+1
       },()=>{
         console.log('step3',this.state.count) // 可以拿到修改后的值
       })
   }
   render(){
    return (
      <div className='listItem'>
        <span onclick={()=>this.addCount()}>{this.state.count}<span>  
      <div>
    )
   }
  } 

创建新的状态

修改state我们都要遵循状态都应该是不可变数据

什么是不可变数据

不可变数据是函数式编程的重要概念,就是我们对已经初始化的数据不进行更改,每次更改都是创建新的对象来承载新的数据状态

状态类型

  • 值类型:string、number、boolean、null、undefined
  • 数组类型
  • 对象
// 1.状态的类型是值类型
this.setState({
    count:1,
    name:'zs',
    show:true
})
// 2.状态的类型是数组
const _books=this.state.books.concat('new book')
   // 或
const _books=[...this.state.books,'new book')]
this.setState({
    books:_books
})
// 2.状态的类型是对象
const _item=Object.assign({},this.state.item,{id:1,ame:'zs'})
    // 或
const _item={...this.state.item,id:1,ame:'zs'}
this.setState({
    item:_item
})

上面创建新的对象都是浅拷贝,如果要深拷贝可以用immutable.js类库 来处理不可变数据。

State进阶

 通过条件判断优化渲染

下面代码是我们渲染一个列表,当我们删除第一行列表的时候,其它2个列表其实没有任何变化,但是它们的render方法还是执行了,执行了render方法其实也要diff对比,当一个大型的项目,这显然也是很耗时的,所以我们要优化它,优化有2种方法:

  1. sholudComponentUpdate(利用这个钩子阻止,如果子组件没有变化就不进行渲染)

  2. PureComponent(利用react提供的组件)

// 父组件
import React,{Component} from 'react';
import ListItem from './listItem'
class Stated extends Component {
    state = { 
        listData: [
            {
              id: 1,
              name: "Sony 65寸高清液晶电视",
              price: 7000,
              stock: 1
            },
            {
              id: 2,
              name: "华为 Meta30",
              price: 6000,
              stock: 2
            },
            {
              id: 3,
              name: "华硕画家国度笔记本电脑",
              price: 10000,
              stock: 3
            }
          ]
     }
     renderList(){
      return  this.state.listData.map(item=>{
            return <ListItem key={item.id} data={item} onDelete={this.handDelete}></ListItem>
        })
     }
     handDelete=(id)=>{
         const listData=this.state.listData.filter(item=>item.id!==id)
         this.setState({
            listData
         })       
     }
    render() {  
        return (  
            <div>
                {this.state.listData.length<=0 && <div>购物车为空</div>}
                {this.renderList()}
            </div>
        );
    }
}
export default Stated;

// 子组件
import React, { Component } from 'react';
class ListItem extends Component {
    state = {  }
    render() { 
        console.log('item render--虚拟dom')
        return (  
            <div>
                <span>{this.props.data.name}</span>
                <button onClick={()=>{
                    this.props.onDelete(this.props.data.id)
                }}>删除</button>
            </div>
        );
    }
}
 
export default ListItem;

sholudComponentUpdate
// 子组件
import React, { Component } from 'react';
class ListItem extends Component {
    state = {  }
    shouldComponentUpdate(nextProps,nextState){
        if(nextProps.data.id===this.props.data.id) return false
        return true
    }
}
export default ListItem;

PureComponent
// 父组件
import React,{PrueComponent} from 'react';
import ListItem from './listItem'
class Stated extends PrueComponent {
    ......
}

单一数据源

尊崇单一数据源,相同的子组件的数据应该由父组件通过props传递子组件,由父组件统一管理,避免造成数据的混乱,使用这个原则的时候,当父组件任何一个 状态的改变,会自动更新子组件这一部分,从上而下传达到子组件的,是同步的方法,子组件想操作数据,由父组件提供更新函数。

状态提升

当我们的子组件都要控制同一个数据源的时候,我们需要将数据提升到它们共同的父组件当中,然后父组件通过props传递给子组件,并由父组件进行统一管理和存储。

为什么使用不可变数据

  1. 可回溯

不直接在数据上修改,方便我们追溯以前的历史记录。

  1. 跟踪数据改变

直接修改数据,跟踪数据的改变需要把当前数据和以前数据的版本进行对比,这样整个对象树都要遍历一次 如果使用不可变数据,创建新的对象,这样我们发现是一个新的对象,那我们不需要对象树对比就知道数据发生了变化,因为对象不是同一个引用了

  1. 确定在react中何时重新渲染

不可变性最主要优势在于它可以帮助我们在react中创建Pure components,我们可以轻松确定不可变数据是否发生了改变,从而确实何时对组件进行重新渲染

有状态组件和无状态组件

Stateful
  • 类组件
  • 有状态组件
  • 容器组件
Stateless
  • 函数组件
  • 无状态组件
  • 展示组件

无状态组件,所有数据源都来自于父组件,它只做展示的作用

尽可能通过状态提升原则,将需要的状态提取到父组件中,而其他的组件使用无状态组件编写

生命周期

三个阶段的生命周期函数

三个阶段生命周期

创建阶段->更新阶段->卸载阶段

创建阶段

创建阶段constructor
  • 初始化内部状态,显性设置和隐性设置

    一个类必须有constructor方法,如果这个方法没有显示定义,一个默认的constructor方法会被添加

  • 需要使用super()调用基类的构造函数

    将父类的props注入给子组件

  • 可以直接修改state

创建阶段componentWillMount(16.3移除)
  • UI渲染完成前调用
  • 只执行一次
  • 这里调用setState不会触发render

更多的时候我们把组件里面的内容,会提前到constructor中,所以这个生命周期函数在项目中我们很少使用

创建阶段render
  • 一个组件必须有的方法(我们的类组件)
  • 返回一个顶级的react元素 只能有一个根元素,不能返回并列元素
  • 渲染的是Dom Tree的一个React对象
 创建阶段componentDidMount
  • UI渲染完成后调用
  • 只执行一次
  • 获取一些外部数据资源

需要注意的是当父组件执行render的时候,当所有子组件都完成了创建,那么父组件才能最终的完成渲染,然后父组件执行componentDidMount

更新阶段

当state和props发生变化时,进入更新阶段

更新阶段componentWillReceiveProps(16.3移除)

只接收props

  • 组件接收到新props的时候触发
  • 在此对比新props和原来的props
  • 不推荐使用
更新阶段shouldComponentUpdate

接收state和props

  • 是否要继续执行render方法
  • 可以由PureComponent自动实现
更新阶段componentDidUpdate
  • 每次UI更新时调用
  • 更新一些外部数据资源

卸载阶段 componentWillUnmount

  • 组件移除时调用
  • 可以用来做资源的释放

图解生命周期

旧的生命周期

新的生命周期

16.3以后移除了 componentWillmount、componentWillReceiveProps、componentWillUpdate

 React组件设计模式

 高阶组件

在业务中可能碰到许多要复用业务逻辑的情况,我们为了避免每个组件都写一段相同逻辑的代码,我们就用高阶组件。

高阶组件是对已有组件的封装,形成新的组件后,有自己的状态和逻辑;并可以传递已有的组件

高阶组件就是接收组件作为参数,并返回新的组件

const NewComponent=higherOrderComponent(OldComponent)

案例:假如多个组件需要鼠标滑入时给个提示,滑出时清空提示,那么可以把这个公共提示抽离出来复用

目录

src/  
    components/
       Item/
         index.jsx
         withTooltip.js

封装Hoc组件(withTooltip.js)

import React from 'react';
const withTooltip=(Component)=>{
    class Hoc extends React.Component {
        state={
            showToolTip:false,
            content:''
        }
        handleOver=(e)=>{
            this.setState({showToolTip:true,content:e.target.innerText})
        }
        handleOut=()=>{
            this.setState({showToolTip:true,content:''})
        }
        render(){
            return(
                <div onMouseOver={this.handleOver} onMouseOut={this.handleOut}>
                    <Component action={this.state} {...props}></Component>
                </div>
            )
        }
    }
    return Hoc
}
export default withTooltip

在需要的组件引入并调用(index.jsx)

import React from 'react';
import withTooltip from './withTooltip'
const ItemA = (props) => {
    return (
        <div className="container">
            <button>Tooltip</button>
            {
                props.action.showToolTip && <div>{props.action.content}</div>
            }
        </div>
        );
}
export default withTooltip(ItemA)

高阶组件特性
  • 一个函数,传入一个组件,返回一个新组件
  • 一般不会有ui展现
  • 提供一些可复用的功能

函数作为子组件(renderProps)

解决复用业务逻辑的问题,是指一种在组件之间使用一个值为函数的props,来共享代码的的设计模式

结构
// 1.定义子组件
render(){
        return (
            <div>
                {this.props.render(this.state)}
            </div>
        )
    }
// 2.使用函数作为Props
<RenderPropComponent render={
    (state)=>{
        <div>
            content
        </div>
    }
}/>

改写上面的案例

目录

src/  
    components/
       Rp/
         index.jsx
         withTooltip.js

定义子组件(withTooltip.js)

import React from 'react';
    class WithTooltip extends React.Component {
        state={
            showToolTip:false,
            content:''
        }
        handleOver=(e)=>{
            this.setState({showToolTip:true,content:e.target.innerText})
        }
        handleOut=()=>{
            this.setState({showToolTip:true,content:''})
        }
        render(){
            return(
                <div onMouseOver={this.handleOver} onMouseOut={this.handleOut}>
                    {this.props.render(this.state)}
                </div>
            )
        }
    }
export default WithTooltip

定义父组件(index.jsx)

import React from 'react';
import WithTooltip from './withTooltip'
const ItemA = (props) => {
    return (
        <div className="container">
              <WithTooltip 
                  render={({showToolTip,content})=>(
                    <div>
                      <button>Tooltip</button>
                        {
                        showToolTip && <div>{content}</div>
                        }
                    </div>
                )}>
            </WithTooltip>
        </div>
        );
}
export default ItemA

 函数作为子组件(Children)

改写成函数作为子组件(更加直观)推荐

定义子组件

import React from 'react';
    class WithTooltip extends React.Component {
        state={
            showToolTip:false,
            content:''
        }
        handleOver=(e)=>{
            this.setState({showToolTip:true,content:e.target.innerText})
        }
        handleOut=()=>{
            this.setState({showToolTip:true,content:''})
        }
        render(){
            return(
                <div onMouseOver={this.handleOver} onMouseOut={this.handleOut}>
                    {this.props.children(this.state)}
                </div>
            )
        }
    }
export default WithTooltip

定义父组件

import React from 'react';
import WithTooltip from './withTooltip'
const ItemB = (props) => {
    return (
        <div className="container">
              <WithTooltip>
                {({showToolTip,content})=>(
                    <div>
                      <button>Tooltip</button>
                        {
                        showToolTip && <div>{content}</div>
                        }
                    </div>
                )}
            </WithTooltip>
    
        </div>
        );
}
export default ItemB

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/482658.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32---DHT11采集与BH1750FVI光照传感器(HAL库、含源码)

写在前面&#xff1a;本节我们学习使用两个常见的传感器模块&#xff0c;分别为DHT11温湿度传感器以及BH1750FVI光照传感器,这两种传感器在对于环境监测中具有十分重要的作用&#xff0c;因为其使用简单方便&#xff0c;所以经常被用于STM32的项目之中。今天将使用分享给大家&a…

错误centos docker版本过低导致 is not a valid repository/tag: invalid reference format

文章目录 错误centos docker版本过低导致 is not a valid repository/tag: invalid reference format1、查看免费主机刚才下载的docker版本2、卸载旧版本3、安装yum依赖包4、安装镜像信息5、安装docker CE6、查看docker版本7、再次运行就成功了&#xff01;&#xff01;&#x…

科技革新背后:码垛机器人在不同领域的实践应用

随着科技的进步&#xff0c;机器人技术已经渗透到各个行业之中&#xff0c;成为提高生产效率、减少人工成本的重要工具。码垛机器人作为自动化技术的杰出代表&#xff0c;其在各个行业中的应用场景日益广泛&#xff0c;从食品饮料到化工产品&#xff0c;再到物流仓储&#xff0…

【国家计算机二级考试C语言.2024】学习备忘录

说明 分值 4060100 40分&#xff1a; 这里面有一大堆程序结果选这题&#xff0c;如果手速还可以。那遇到有疑问的情况就自己去倒计算器的ad E上面去打一打。能够跑出来&#xff0c;结果那是100%的没问题。 有些概念题比较讨厌&#xff0c;只能自己去记忆了。要去背诵熟熟的。…

取消springboot中的Test类中的日志打印

使用SpringBootTest注解进行单元测试时, 打印东西的时候,总会伴随很多的无关紧要的日志信息&#xff0c;影响观感。去掉这些日志应该怎么做呢 ? 两个步骤: 第一步、修改application.properties logging.level.rootoff logging.level.org.springframeworkoff # 关闭baner信息…

阿猪写作能用吗 #媒体#微信

阿猪写作是一个非常实用的论文写作工具&#xff0c;它不仅能帮助用户快速完成论文写作&#xff0c;还可以提供查重降重的功能&#xff0c;帮助用户确保论文的原创性。在当今社会&#xff0c;论文写作是学术界和科研领域最重要的工作之一&#xff0c;而阿猪写作的出现无疑是给这…

案例实践 | 基于长安链的煤质检测智慧实验室

案例名称-煤质检测智慧实验室 ■ 建设单位 国能数智科技开发&#xff08;北京&#xff09;有限公司 ■ 用户群体 煤炭生产单位、电力单位、化工单位等产业链上下游单位 ■ 应用成效 化验效率提升50%&#xff0c;出验时间缩短40%&#xff0c;提高化验数据市场公信力 案例…

Linux(Centos)安装mysql 8 并且使用systemctl管理服务

1.下载mysql包 地址 MySQL :: Download MySQL Community Server (Archived Versions) 注&#xff1a;下载我圈住的减压之后里面会有tar.gz 再次减压才会是软件主体 2.安装和准备 yum -y install numactl 安装numactl tar -xvf mysql-8.0.30-el7-x86_64.tar 拆分 …

rider下ef core迁移

新建数据库 create database mockstu新建web项目 安装Microsoft.EntityFrameworkCore.SqlServer包 设置连接字符串 新建model using MockStuWeb.Models.EnumTypes; using System.ComponentModel.DataAnnotations;namespace MockStuWeb.Models {/// <summary>/// 学生…

百度文心一言(ERNIE bot)API接入Android应用

百度文心一言&#xff08;ERNIE bot&#xff09;API接入Android应用实践 - 拾一贰叁 - 博客园 (cnblogs.com) Preface: 现在生成式AI越来越强大了&#xff0c;想在android上实现一个对话助手的功能&#xff0c;大概摸索了一下接入百度文心一言API的方法。 与AI助手交换信息的…

分布式搜索引擎-DSL查询文档

分布式搜索引擎-DSL查询文档 文章目录 分布式搜索引擎-DSL查询文档1、DSL Query的分类1.1、全文检索查询1.2、精确查询1.3、地理查询1.4、复合查询1.5、Function Score Query1.6、复合查询Boolean Query 2、搜索结果处理2.1、排序2.2、分页2.3、深度分页2.4、高亮 1、DSL Query…

鸿蒙OpenHarmony开发实战:【MiniCanvas】

介绍 基于OpenHarmony的Cavas组件封装了一版极简操作的MiniCanvas&#xff0c;屏蔽了原有Canvas内部复杂的调用流程&#xff0c;支持一个API就可以实现相应的绘制能力&#xff0c;该库还在继续完善中&#xff0c;也欢迎PR。 使用说明 添加MiniCanvas依赖 在项目entry目录执行…

混合云构建-使用 Azure ExpressRoute 建立从本地到 Azure 虚拟网络的专用连接

如果有大量业务数据需要在本地数据中心和azure私有网络进行传输&#xff0c;同时保证带宽和时延的情况需要使用 ExpressRoute 设置从本地网络到 Azure 中的虚拟网络的专用连接。以下是实操步骤供参考&#xff1a; 一、创建和预配 ExpressRoute 线路 登录 Azure 门户。 在页面…

为什么独享ip会更高效?

随着互联网的蓬勃发展&#xff0c;代理IP因其特性&#xff0c;也备受关注&#xff0c;代理IP又有分共享代理IP和独享代理IP&#xff0c;但&#xff0c;无论是在数据采集方面&#xff0c;还是在其他业务场景上&#xff0c;独享代理IP似乎会更受用户欢迎一点&#xff0c;这到底是…

【Flask】Flask数据迁移操作

Flask数据迁移操作 前提条件 安装第三方包&#xff1a; # ORM pip install flask-sqlalchemy # 数据迁移 pip install flask-migrate # MySQL驱动 pip install pymysql # 安装失败&#xff0c;指定如下镜像源即可 # pip install flask-sqlalchemy https://pypi.tuna.tsinghu…

Typecho如何去掉/隐藏index.php

Typecho后台设置永久链接后&#xff0c;会在域名后加上index.php&#xff0c;很多人都接受不了。例如如下网址&#xff1a;https://www.jichun29.cn/index.php/archives/37/&#xff0c;但我们希望最终的形式是这样&#xff1a;https://www.jichun29.cn/archives/37.html。那么…

Lua热更新(Lua)

-- [[]] print 下载Lua For Windows Sublime Text&#xff08;仅用于演示&#xff0c;实际项目使用VsCode&#xff09; CtrlB运行 语法基础 基础类型&#xff1a;nil number string boolean 运算符&#xff1a;and-or-not ~ ^ if-then-end-elseif-else while-do-…

Kotlin零基础入门到进阶实战

教程介绍 Kotlin现在是Google官方认定Android一级开发语言&#xff0c;与Java100%互通&#xff0c;并具备诸多Java尚不支持的新特性&#xff0c;每个Android程序员必备的Kotlin课程&#xff0c;每个Java程序员都需要了解的Kotlin&#xff0c;掌握kotlin可以开发Web前端、Web后…

【机器学习300问】46、什么是ROC曲线?

一、二分类器的常用评估指标有哪些&#xff1f; 二分类器是机器学习领域中最常见的也是应用最广泛的分类器。评价二分类器的指标也很多&#xff0c;下面列出几个我之前重点写文章介绍过的指标。 &#xff08;1&#xff09;准确率&#xff08;Accuracy&#xff09; 定义为分类正…

VSGitHub项目联动(上传和克隆),创建你的第一个仓库,小白配置

目录&#xff1a; 前言一&#xff0c;基本说明1.1名词概念1.2必配条件 二&#xff0c;配置方法2.1本地生成密钥2.2云端代码托管平台SSH配置添加&#xff08;GitHub&#xff09;2.3VS项目配置 三&#xff0c;参考四&#xff0c;一些讨论 前言 &#x1f308;在编写VS代码项目时&a…