react笔记_06类组件

news2024/11/26 18:37:29

目录

    • 复习
      • 展开运算符
    • 组件
      • 什么叫做组件?
      • 分类
      • 类组件
        • es6新增构造函数
        • 语法
        • 类组件渲染
        • 类组件的this指向
        • 类组件的三大属性
          • state
            • 作用
            • 语法-初始化数据
            • 语法-修改state数据
            • 语法-获取state中的数据
            • 案例
          • props
            • propTypes属性(prop-types库)
            • defaultProps属性
          • refs
            • [1] 字符串形式的ref
            • [2] 回调形式的ref
            • createRef形式的ref
        • 类组件的生命周期

复习

展开运算符

<script>
  let arr1 = [1, 3, 5, 7, 9]
  let arr2 = [2, 4, 6, 8, 10]
  // 【1】展开一个数组
  console.log(...arr1); 
  // 【2】合并数组
  let arr3 = [...arr1, ...arr2]

  // 【3】在函数接收参数使用中使用
  function sum(...numbers) {
    return numbers.reduce((preValue, currentValue) => {
      return preValue + currentValue
    })
  }
  console.log(sum(1, 2, 3, 4));

  // 【4】构造字面量对象时使用展开语法
  let person = {name: 'tom', age: 18}
  let person2 = {...person}

  // 【5】合并修改
  let person3 = {...person, name: 'jack', address: "地球"}
  console.log(person3)// {address: "地球", age: 18, name: "jack"}

  // 注意:展开运算符不能展开对象
  //console.log(...person); //报错,
</script>

总结:
展开运算符可以用来展开数组、合并数组、构造字面量对象时使用展开语法、合并修改,但是却不可以展开对象

组件

什么叫做组件?

用来实现局部功能效果的代码和资源的集合叫做组件(html/css/js/image等)

分类

在react中组件分为函数式组件与类式组件;

今天主要了解的是类式组件~

类组件

es6新增构造函数

es6新增的构造函数-class关键字

语法

在react中 类组件必须继承于React.Component这个组件(React.Component组件中存在生命周期函数等方法)

import React from 'react'
class 组件名 extends React.Component{
  render(){
    return vodom
  }
}
  • [1] 每一个类组件强制存在一个render函数,这个函数的返回值为jsx元素(vdom)
  • [2] vdom必须存在一个根标签,最外层多个标签并列是不合法的;
  • [3] 在vdom中可以插入js表达式,表达式返回的结果会相应的渲染到页面上面

类组件渲染

  • [1]查看组件首字母大/小写:

    若是首字母小写则默认为html标签,会去寻找对应的html标签并渲染,若是没有找到对应的html标签则会报错;

    若是首字母大写则默认为组件,会去寻找对应的组件并渲染,若是没有找到对应的组件就会报错;

    tips: 组件的组件名 首字母必须 大写,否则会被认作html标签

  • [2]开始渲染(此处以类组件为例)

    (1)通过new关键字去实例化对象-> 在通过new关键字去实例化对象时会自动调用constructor构造器创建实例化对象并修改this指向;
    (2)在获取到实例化对象之后,react会通过实例化对象调用render函数获取vdom并渲染;

    tips: 若是想看详细渲染、更新、销毁过程可见类组件的生命周期

类组件的this指向

this指向的原则是:谁调用指向谁

接下来我将尽可能的列举出所有类组件中方法调用,并说明方法的this指向

import React from 'react'

class App extends React.Component{
  render(){
    // 在渲染过程中也讲述过,render函数是获取到实例化对象之后由实例化对象调用的,因此this指向的是实例化对象
    console.log('render-this', this)
    return (
      <div>
        <p onClick={this.say}>111</p>
        <p onClick={this.say2}>222</p>
      </div>
    )
  }

  say(){
    // 该方法的调用是绑定在vdom上;
    // 在渲染-获取vdom时若是发现vdom上存在事件绑定则会执行被绑定的代码得到的值在事件被触发时直接调用/执行,因此this指向undefined(严格模式下)
    console.log('恭喜发财', this)
  }

  say2 = ()=>{
    // 该函数为箭头函数,需要通过作用域链寻找this,因此this指向实例化对象
    console.log('恭喜发财*2', this)
    this.say3()
  }

  say3(){
    // 该函数是实例化对象直接调用,因此this指向实例化对象
    console.log('恭喜发财*3', this)
  }
}

export default App;

类组件的三大属性

react的三大属性其实是实例化对象的三大属性,由于函数组件是没有实例化的,因此将这三大属性称为类组件的三大属性。

state
作用

用于存储数据,状态(数据)驱动试图

语法-初始化数据

state必须是一个对象

  • 若需要声明constructor函数则可以将state初始化写在constructor中

    class App extends React.Component{
      constructor(){
        super()
        this.state={
          ishot:true
        }
      }
      render(){
        return (
          <div>
            <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
          </div>
        )
      }
    }
    

    此时页面显示‘今天天气炎热’

  • 若是不需要声明constructor函数则可以直接将state初始化在类中

    class App extends React.Component{
      state={
        ishot:true
      }
      render(){
        return (
          <div>
            <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
          </div>
        )
      }
    }
    
语法-修改state数据

若是直接通过点语法去修改state中的数据,虽然数据变化了,但是却不会重新渲染数据

class App extends React.Component{
  state={
    name:'chaochao',
    ishot:true
  }
  render(){
    return (
      <div>
        <p>今天天气{this.state.ishot?'炎热':'凉爽'}</p>
        <p onClick={this.editstate}>改变状态</p>
      </div>
    )
  }
  editstate = ()=>{
    this.state.ishot = !this.state.ishot
    console.log('state', this.state.ishot) // false、true、false...
  }
}

可以发现,虽然每次打印ishot的值发生了变化,但是页面显示的文本一直是‘今天天气炎热’不变。

在react中可以用过setstate函数去修改state中的值,修改方式如下
语法

setState(Object/Function,[callback])
  • 方式1

    setState({属性名:属性值})
    
  • 方式2

    setState((state,props)=>{
    return {属性名: 属性值}
    })
    

    若是第一个参数为函数:当调用setState函数时,react会自动调用该函数,并将当前state与props传入,因此在该函数中是可以获取当前实例对象的state 与props的。

使用时机-什么时候使用对象/函数呢?

  • 若是新状态不依赖于原状态 -> 推荐使用对象式的state
  • 若是新状态依赖于原状态 -> 推荐使用函数式的state(因为这样不需要获取state中的数据了)
  • 举例说明:增加count的值需要依赖于当前state推荐使用函数
    class App extends React.Component{
      state={
        name:'chaochao',
        ishot:true,
        count:0
      }
      render(){
        return (
          <div>
            <p>{this.state.count}</p>
            <p onClick={this.editstate}>改变状态</p>
          </div>
        )
      }
      editstate = ()=>{
        // this.setState({count: ++this.state.count})
        this.setState(state=> ({count: ++state.count}))
      }
    }
    
    对象式的setState是函数式的setState的语法糖

注意点

[1] 使用setState去修改数据是替换还是合并?

  • 使用内置API setState去修改state中的数据,这个数据的修改不是替换而是合并
  • 举例说明
    • 在初始化时数据state = {isHot:false, xxx:111} 有两条数据
    • 当通过this.setState({isHot:true})去修改数据
    • 再次获取数据时 {isHot:true, xxx:111} xxx不会被覆盖
语法-获取state中的数据

直接通过点语法去获取state中的数据即可。需要注意的是setstate修改state中的数据是异步的,因此获取state中数据时也要注意时机。

举例说明

class App extends React.Component{
  state={
    name:'chaochao',
    ishot:true,
    count:0
  }
  render(){
    return (
      <div>
        <p>{this.state.count}</p>
        <p onClick={this.editstate}>改变状态</p>
      </div>
    )
  }
  editstate = ()=>{
    this.setState(state=> ({count: state.count+1}))
    console.log('state', this.state.count)
  }
}

上述案例中 在第一次点击时 页面显示的数值是1,而打印的还是之前的值0。

这是因为setState更新数据是异步的,若是想要在通过setState修改数据后,立即拿到修改后的数据,可以使用setState的第二个参数

   this.setState(stateChange,[callback])

第二个参数是一个回调函数,该回调函数的执行时机是在 在此次数据更新的render函数调用之后执行 : setState->render -> callback

editstate = ()=>{
  this.setState(state=> ({count: state.count+1}),()=>{
    console.log('state', this.state.count)
  })  
}

此时第一次点击,控制台打印的就是1了

案例

案例:默认显示文本 今天天气炎热,当点击文本时显示 今天天气凉爽

class App extends React.Component{
  state={
    ishot:true
  }
  render(){
    const {ishot} = this.state
    return (
      <div>
        <p onClick={this.editstate}>今天天气{ishot?'炎热':'凉爽'}</p>
      </div>
    )
  }
  editstate = ()=>{
    this.setState(state=> ({ishot: !state.ishot}))
  }
}
props

和vue相同,props在react中的作用也是进行父子传值。

  • 在父组件中: 将需要传递给子组件的数据以 属性 的形式添加在子组件标签上
    <子组件 属性名1=属性值1 属性名2=属性值2 .../>
    
  • 在子组件中:通过实例化对象的props属性进行接收
    this.props // 将接收到props这个对象中
    

示例如下:

import React from 'react'

class People extends React.Component{
 render(){
   console.log('props', this.props) // {name: 'chaochao', age: 18, area: '中国'}
   return 111
 }
}

class App extends React.Component{
 render(){
   return (
     <div>
       <People name='chaochao' age={18} area='中国'/>
     </div>
   )
 }
}

export default App;

同样的,我们可以约定规范 如传递数据的数据类型、是否可以为空、设置默认值等。

propTypes属性(prop-types库)

在 React v15.5 版本之前,在React上存在PropTypes函数用于进行props属性的类型交验。

从 React v15.5 开始 ,React.PropTypes 助手函数已被弃用,更推荐使用 prop-types 库 来定义contextTypes。

使用语法如下:

  • 下载prop-types库
      npm i prop-types
    
  • 引入prop-types库
      import PropTypes from 'prop-types'
    
  • 给类组件添加propTypes属性进行属性限制,限制规则如下
    PropTypes.number // 数据为数字类型
    PropTypes.string // 数字为字符串类型
    PropTypes.bool // 数据为boolean值
    PropTypes.symbol // 数据为symbol值
    PropTypes.array // 数据为数组类型
    PropTypes.func // 数据为函数类型
     PropTypes.element // 数据为React元素
     PropTypes.instanceOf(Message) //prop 是类的一个实例
     PropTypes.oneOf(['News', 'Photos']) // prop是一个枚举
     PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
      PropTypes.instanceOf(Message)
    ]) // prop是多种类型之一
    PropTypes.func.isRequired // prop是函数类型且必填
    PropTypes.any.isRequired // prop可以是任意类型但必填
    
  • 语法如下:
      static propTypes = {
        属性值: 规则限制
      }
    
      Component.propTypes = {
        属性值: 规则限制
      }
    
  • 举例说明
    import React from 'react'
    import PropTypes from 'prop-types'
    import './App.css';
    
    // 子组件 - 希望name属性值为字符串类型且必填,sex属性为字符串类型默认值为‘weizhi’(默认值后面讲解defaultProps属性时再进行设置), age属性值为数字类型
    class People extends React.Component{
      static propTypes = {
        name: PropTypes.string.isRequired,
        sex: PropTypes.string,
        age: PropTypes.number
      }
      render(){
        // console.log('props', this.props)
        return (
          <>
            son
          </>
        )
      }
    }
    
    class App extends React.Component{
      render(){
        return (
          <div>
            <People name='chaochao' sex='nv' age='18'/>
          </div>
        )
      }
    }
    
    
    export default App;
    
    此时name属性、sex属性赋值没有问题,但是age属性的赋值却不符合要求,因此在控制台会给出警告(但是不会报错),如下:
    在这里插入图片描述
defaultProps属性

propTypes属性用于规范prop的类型,defaultProps属性用于设置属性默认值,语法如下:

 static propTypes = {
   属性值: 规则限制
 }
Component.propTypes = {
 属性值: 规则限制
}

上面案例为sex添加默认值如下

import React from 'react'
import PropTypes from 'prop-types'
import './App.css';

// 子组件- 希望name属性值为字符串类型且必填,sex属性为字符串类型默认值为‘weizhi’, age属性值为数字类型
class People extends React.Component{
  static propTypes = {
    name: PropTypes.string.isRequired,
    sex: PropTypes.string,
    age: PropTypes.number
  }
  static defaultProps = {
    sex:'weizhi'
  }
  render(){
    console.log('props', this.props) // {name: 'chaochao', age: 18, sex: 'weizhi'}
    return (
      <>
        son
      </>
    )
  }
}

class App extends React.Component{
  render(){
    return (
      <div>
        <People name='chaochao' age={18}/>
      </div>
    )
  }
}
refs

在react中尽量不要直接操作dom,如果要操作dom,可以使用refs;
定义ref的形式有3种

[1] 字符串形式的ref

字符串形式的ref与Vue中ref的使用相同~

每个类实例化对象身上都存在一个refs属性,该属性为一个对象。

若是想要获取某个dom,则可以给该vdom上添加ref属性-属性值为字符串。添加之后就会将该dom以键值队的形式添加到refs对象中。

若是没有给任何vdom添加ref属性,则该实例化对象的refs属性为一个空对象。

获取dom元素需要等待dom元素渲染完毕,在render里面是获取不到dom元素的,如下:

class App extends React.Component{
  render(){
    console.log('refs', this.refs) // {}
    return (
      <div ref='box'></div>
    )

  }
}

在渲染完毕之后就可以正常获取dom元素了

class App extends React.Component{
  render(){
    return (
      <div ref='box'>
        <button onClick={this.getValue}>点我显示数据</button>
      </div>
    )

  }
  getValue=()=>{
    console.log('refs', this.refs) // refs {box: div}
  }
}

需要注意的是该形式在官方不推荐使用,因为使用此方式定义ref若是多次定义—效率有很大的问题。
若是使用字符串形式获取dom,则会在控制台提示如下
在这里插入图片描述

[2] 回调形式的ref

在了解回调形式的ref之前需要先了解什么是回调?

  • [1] 定义了一个函数
  • [2] 没有主动调用函数
  • [3] 函数最终执行了

什么是回调形式的ref呢?

若是想获取dom元素,就在vdom上添加ref属性只不过属性值是一个函数。

在渲染vdom时,若是发现ref属性值是一个函数,react会调用这个函数并且将该dom作为参数传入。

class App extends React.Component{
  render(){
    return (
      <div ref={dom => {
        console.log('dom', dom)
        this.box = dom // 获取到dom元素进行赋值
      }}>
        <button onClick={this.getValue}>点我显示数据</button>
      </div>
    )

  }
  getValue=()=>{
    console.log('box', this.box) // dom元素
  }
}

但是像以上这种将回调函数写在行内的会存在一个问题:更新时重新调用render函数时会重新调用该回调函数两次

class App extends React.Component{
  state = {
    hot: true
  }
  render(){
    return (
      <div ref={dom => {
        console.log('dom', dom)
        this.box = dom // 获取到dom元素进行赋值
      }}>
      <button onClick={()=>{
        this.setState({hot: false})
      }}>点我修改hot</button>
      </div>
    )

  }
}

在上述案例中,当我点击“点我修改hot”时,发现回调函数执行了两次结果如下:
在这里插入图片描述
第一次获取的dom是个空值,第二次获取真实dom。

原来这个问题产生的根本原因是将回调函数写在了行内

  • 当将函数写在行内时
    • 渲染-> 执行render函数时-> 发现ref绑定的是一个函数,会自动调用该函数并将该dom元素作为参数传入;
    • 更新 ->重新调用render函数,此次执行过程中会调用2次该函数—第一次传入的参数为null,第二次传入的才是dom
      没有造成实质的影响,因为这两次调用过程很短暂;
  • 不将回调函数写在行内
    • 渲染-> 执行render函数时-> 发现ref绑定的是一个函数,会自动调用该函数并将该dom元素作为参数传入;
    • 更新 -> 不调用此函数;
createRef形式的ref

在React上存在createRef方法,该方法被调用后会返回一个对象

{
  current:... 
}

该容器可以存储ref所标识的节点(存储在current属性中),该容器是专人专用的(一个容器仅能存储一个dom)

this.input = React.createRef() // 产生一个容器
<input ref={ this.input }> //  存储
const {current} = this.input // 容器的current属性表示当前的dom元素

举例说明

class App extends React.Component{
  box = React.createRef()
  render(){
    return (
      <div ref={this.box}>
      <button onClick={()=>{
        console.log('box', this.box.current)
      }}>点我修改hot</button>
      </div>
    )
  }
}

类组件的生命周期

生命周期

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于UFLD-v2的改进:UFLD-v2-plus

1 待解决问题 UFLD-v2是一个非常优秀的车道线检测模型。也有一些问题。 1 参数量太大&#xff0c;一个模型600M。 2 不能区分车道线。 2 工作内容 改进方法如下 2.1 降低参数量 对模型网络逐层参数量&#xff0c;可以发现&#xff0c;86%&#xff08;很久之前分析的&…

基于STM32+华为云IOT设计的智能浇花系统

一、前言 随着社会的不断发展和人们生活水平的逐渐提高,人们逐渐追求高质量的生活,很多人都会选择在家里或办公室种植一些花卉以净化家庭空气,陶冶情操,但是很多人忙于工作、学习、出差、旅游或者一些其他的原因,不能及时地对花卉进行照料,短时间内导致很多花卉因缺水分…

100天精通Golang(基础入门篇)——第13天:深入解析Go语言中的字符串(string)及常用函数应用

&#x1f337; 博主 libin9iOak带您 Go to Golang Language.✨ &#x1f984; 个人主页——libin9iOak的博客&#x1f390; &#x1f433; 《面试题大全》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &#x1f30a; 《I…

怎么用爱问转换工具在线拆分PDF文件

我们平时在工作中会用到很多PDF文件&#xff0c;有的PDF文件内容很多&#xff0c;里面也有许多分类类别&#xff0c;其实对于这种内容多的PDF文件&#xff0c;可以使用拆分的方式&#xff0c;来获取自己需要的材料&#xff0c;那么&#xff0c;如何快速拆分PDF文件呢&#xff1…

VSCode离线安装Remote-SSH插件

最近想要在VSCode上安装Remote-SSH插件&#xff0c;以便可以远程登录云服务器进行开发或者文件编辑、文件传输等功能&#xff1b;但是VSCode中在线安装一直失败&#xff0c;所以记录一下离线安装的方法&#xff1b; 文章目录 一、下载VSCode Remote-SSH的离线插件&#xff0c;即…

python: PyCharm 2023.1打包项目成执行程序

IDE 最底部&#xff1a; pyinstaller -i heart.ico -D main.py 生成成功

Jenkins基础介绍以及docker安装Jenkins

Jenkins基础介绍以及docker安装Jenkins 什么是Jenkins&#xff1f; Jenkins是一个可扩展的持续集成引擎 持续集成就是通常说的CI&#xff08;Continues Integration&#xff09; 每次集成都通过自动化的构建&#xff08;包括编译&#xff0c;发布&#xff0c;自动化测试&am…

同一局域网内IP 192.168.1.10 和 IP 10.10.10.8 可以互相访问吗?

同一局域网内IP 192.168.1.10 和 IP 10.10.10.8 可以互相访问吗&#xff1f; 1、网上邻居的方式&#xff1a; 鼠标点击 我的电脑 属性 计算机名&#xff0c;查看一下 计算机名&#xff08;这个可以点击更改&#xff0c;自己设定和更改&#xff09; 查看一下工作组&#xff0c;一…

基于node.js中的serialport模块实现无线传感网上位机功能

半个月前的无线传感网课设上位机的实现遇到了很多困难&#xff0c;特写此文章给有需要的朋友一些帮助&#xff0c;欢迎私信探讨 文章目录 前言一、node.js中的serialport模块二、express框架三、echarts实现拓扑图四、实现下行数据五、成果展示总结 前言 本文所要实现的功能以…

【React】next+antd报错:Module not found: Can‘t resolve ‘antd/es/content‘

Antd Next手册&#xff1a;https://ant.design/docs/react/use-with-next-cn 报错场景 根据官方手册进行项目创建 yarn create next-app antd-demoyarn add antd 得到以下环境&#xff1a; EnvironmentInfoantd5.6.4next13.4.8react18.2.0 安装完依赖后&#xff0c;运行y…

java方法详解

1. 方法概述 1.1 什么是方法 方法&#xff08;method&#xff09;是将具有独立功能的代码块组织成为一个整体&#xff0c;使其具有特殊功能的代码集 注意&#xff1a; 方法必须先创建才可以使用&#xff0c;该过程称为方法定义方法创建后并不是直接运行的&#xff0c;需要手动…

日本 NFT 项目概览与特点总结

日本的 NFT 市场 日本的 NFT 市场起源于与国内动漫和娱乐偶像的合作&#xff0c;重点关注本土文化&#xff0c;文化成为日本 NFT 项目的重要基石。 关键要点&#xff1a; 日本的 NFT 产业具有三个特点&#xff1a;广泛的知识产权&#xff08;IP&#xff09;、低 FUD 水平以及…

Ka/Ks介绍和分析

什么是Ka/Ks? 在遗传学中&#xff0c;Ka/Ks表示的是两个蛋白编码基因的非同义替换率&#xff08;Ka&#xff09;和同义替换率&#xff08;Ks&#xff09;之间的比例。这个比例可以判断是否有选择压力作用于这个蛋白质编码基因。 如果你手头有两个不同物种的同一个基因的序列…

JavaWeb项目-超市订单管理系统【Day02】

密码修改 1、编写接口方法和mybatis的SQL映射文件 Mybatis配置多参数SQL语句 当我们的SQL语句中有多个参数的时候&#xff0c;需要设置每个参数名对应的接口参数&#xff0c;不然会报错&#xff1a; Parameter ‘id’ not found. Available parameters are [argl, argg, par…

【设计模式】第十二章:观察者模式详解及应用案例

系列文章 【设计模式】七大设计原则 【设计模式】第一章&#xff1a;单例模式 【设计模式】第二章&#xff1a;工厂模式 【设计模式】第三章&#xff1a;建造者模式 【设计模式】第四章&#xff1a;原型模式 【设计模式】第五章&#xff1a;适配器模式 【设计模式】第六章&…

chatGPT如何开启 Browsing 功能,实现即时联网查询?

Openai 为每一个 chatGPT Plus 用户都开放了 Browsing 和 plugins 功能。 前者可以在 ChatGPT 觉得有必要的时候&#xff08;比如你问它今天的新闻&#xff09;&#xff0c;自动联网查询&#xff0c;后者是第三方开发者开发的插件&#xff0c;数量繁多&#xff0c;可以解决各种…

Git 常用操作总结

版本控制系统&#xff08;VCS&#xff09;是管理文件和目录所做的更改的工具&#xff0c;每一次提交便记录下目录及其文件的内容&#xff0c;以及较上一版本的更改。通过这样去跟踪项目的更改过程&#xff0c;方便与他人进行协作&#xff0c;或者撤销不想要的更改以回退到此前的…

DR模式部署LVS负载均衡集群

目录 一、配置负载调度器 1.配置虚拟 IP 地址&#xff08;VIP&#xff1a;192.168.146.180&#xff09; 2.调整 proc 响应参数 3. 配置负载分配策略 ​编辑二、部署共享存储&#xff08;NFS服务器&#xff1a;192.168.146.20&#xff09; 三、配置节点服务器 1.配置虚拟…

解决vue中mapbox地图显示一半的问题

解决vue中mapbox地图显示一半的问题 问题描述&#xff1a; 在vue中创建mapbox地图&#xff0c;地图只显示一般&#xff0c;查看浏览器开发者工具。发现将canvas.mapboxgl-canvas 的position:absolute去掉就解决了 。 代码修改&#xff1a;获取到canvas.mapboxgl-canvas,并修改…

zookeeper第一课-Zookeeper特性与节点数据类型详解

1、Zookeeper特性与节点数据类型详解 ZooKeeper 是一个开源的分布式协调框架&#xff0c;是Apache Hadoop 的一个子项目&#xff0c;主要用来解决分布式集群中应用系统的一致性问题。 Zookeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来&#xff0c;构成一…