React快速入门(二)组件与函数

  • React快速入门(二)组件与函数
    • React脚手架
    • React组件化开发
    • setState原理
    • React更新机制
    • 使用ref
    • 受控/非受控组件
    • 高阶函数
    • Portals/fragment/StrictMode


React快速入门(二)组件与函数

React脚手架

  • 脚手架让项目从搭建到开发,再到部署,整个流程变得快速和便捷
  • 创建:
    1. create-react-app 项目名称(全小写)
    2. cd 项目名称
    3. yarn start

React组件化开发

  • React的组件相对于Vue更加的灵活和多样,按照不同的方式可以分成很多类组件:
    • 根据组件的定义方式,可以分为:函数组件(Functional Component )类组件(Class Component)
    • 根据组件内部是否有状态需要维护,可以分成:无状态组件(Stateless Component )有状态组件(Stateful Component)
    • 根据组件的不同职责,可以分成:展示型组件(Presentational Component)容器型组件(Container Component)
  • 最主要是关注数据逻辑和UI展示的分离:
    • 函数组件、无状态组件、展示型组件主要关注UI的展示
    • 类组件、有状态组件、容器型组件主要关注数据逻辑

类组件

  • 组件的名称是大写字符开头(无论类组件还是函数组件)

  • 类组件需要继承自React.Component

  • 类组件必须实现render函数

  • 使用class定义一个组件:

    • constructor是可选的,我们通常在constructor中初始化一些数据
    • this.state中维护的就是我们组件内部的数据
    • render()方法是 class组件中唯一必须实现的方法

render函数的返回值

  • 当render被调用时,它会检查this.props和 this.state的变化并返回以下类型之—:
  • React元素:
    • 通常通过JSX创建
    • 例如:< div />会被React渲染为DOM节点,< MyComponent/>会被React渲染为自定义组件
    • 无论是< div/>还是< MyComponent />均为 React元素
  • 数组或 fragments:使得render方法可以返回多个元素
  • Portals:可以渲染子节点到不同的DOM子树中
  • 字符串或数值类型:它们在 DOM中会被渲染为文本节点
  • 布尔类型或 null:什么都不渲染

函数组件

  • 函数组件是使用function来进行定义的函数,只是这个函数会返回和类组件中render函数返回一样的内容。
  • 函数组件有自己的特点:
    • 没有生命周期,也会被更新并挂载,但是没有生命周期函数
    • this关键字不能指向组件实例(因为没有组件实例);
    • 没有内部状态(state) ;

生命周期

在这里插入图片描述

  • Constructor

    • 如果不初始化state或不进行方法绑定,则不需要为React组件实现构造函数。
    • constructor中通常只做两件事情:
      • 通过给this.state赋值对象来初始化内部的state
      • 为事件绑定实例(this)
  • componentDidMount

    • componentDidMount()会在组件挂载后(插入DOM树中)立即调用。
    • 依赖于DOM的操作可以在这里进行
    • 在此处发送网络请求最好的地方(官方建议)
    • 可以在此处添加一些订阅(会在componentWillUnmount取消订阅)
  • componentDidUpdate

    • componentDidUpdate()会在更新后会被立即调用,首次渲染不会执行此方法。
    • 当组件更新后,可以在此处对 DOM进行操作;如果对更新前后的props进行了比较,也可以选择在此处进行网络请求
  • componentWillUnmount

    • componentWillUnmount()会在组件卸载及销毁之前直接调用
    • 在此方法中执行必要的清理操作;例如,清除 timer,取消网络请求或清除在componentDidMount()中创建的订阅等;
  • getDerivedStateFromProps: state的值在任何时候都依赖于props时使用;该方法返回—个对象来更新state;

  • getSnapshotBeforeUpdate:在React更新DOM之前回调的一个函数,可以获取DOM更新前的—些信息(比如说滚动位置);

  • shouldComponentUpdate:该生命周期函数很常用,做性能优化

React组件间通信

  • 父子组件
    • 父组件通过属性=值的形式来传递给子组件数据
    • 子组件通过props参数获取父组件传递过来的数据
//父组件
<MainBanner banners={banners} title="轮播图"/>//子组件
import React, { Component } from 'react'
import PropTypes from "prop-types"export class MainBanner extends Component {constructor(props) {super(props)this.state = {}}render() {const { title, banners } = this.propsreturn (<div className='banner'>...</div>)}
}// MainBanner传入的props类型进行验证
MainBanner.propTypes = {banners: PropTypes.array.isRequired,title: PropTypes.string
}// MainBanner传入的props的默认值
MainBanner.defaultProps = {banners: [],title: "默认标题"
}export default MainBanner
  • 子父组件
    • 通过props传递消息,只是让父组件给子组件传递一个回调函数,在子组件中调用这个函数即可
//父组件
export class App extends Component {constructor() {super()this.state = {counter: 100}}changeCounter(count) {this.setState({ counter: this.state.counter + count })}render() {const { counter } = this.statereturn (<div><h2>当前计数: {counter}</h2><AddCounter addClick={(count) => this.changeCounter(count)}/><SubCounter subClick={(count) => this.changeCounter(count)}/></div>)}
}
//子组件
export class AddCounter extends Component {addCount(count) {this.props.addClick(count)}render() {return (<div><button onClick={e => this.addCount(1)}>+1</button><button onClick={e => this.addCount(5)}>+5</button><button onClick={e => this.addCount(10)}>+10</button></div>)}
}

React中的插槽(slot)实现

  • 组件的children子元素

  • props属性传递React元素

//父组件
export class App extends Component {render() {const btn = <button>按钮2</button>return (<div>{/* 1.使用children实现插槽 */}<NavBar><button>按钮</button><h2>哈哈哈</h2><i>斜体文本</i></NavBar>{/* 2.使用props实现插槽 */}<NavBarTwo leftSlot={btn}centerSlot={<h2>呵呵呵</h2>}rightSlot={<i>斜体2</i>}/></div>)}
}
//子组件一 -- 使用children 注意一个和多个时的children类型
export class NavBar extends Component {render() {const { children } = this.propsconsole.log(children)return (<div className='nav-bar'><div className="left">{children[0]}</div><div className="center">{children[1]}</div><div className="right">{children[2]}</div></div>)}
}
//子组件二 -- 使用props
export class NavBarTwo extends Component {render() {const { leftSlot, centerSlot, rightSlot } = this.propsreturn (<div className='nav-bar'><div className="left">{leftSlot}</div><div className="center">{centerSlot}</div><div className="right">{rightSlot}</div></div>)}
}

Context应用场景

  • 如果层级很多的话,一层层传递是非常麻烦,并且代码是非常冗余的:

    • React提供了—个APl: Context;
    • Context 提供了一种在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递props;
    • Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言;
  • Context的使用

  1. React.createContext
    • 创建一个需要共享的Context对象;如果一个组件订阅了Context,那么这个组件会从离自身最近的那个匹配的Provider中读取到当前的context值(就近原则)
//defaultValue
const ThemeContext = React.createContext({ color: "blue", size: 10 })
const UserContext = React.createContext()
  1. Context.Provider
    • Provider接收一个value属性,传递给消费组件;一个Provider可以和多个消费组件有对应关系;多个Provider也可以嵌套使用,里层的会覆盖外层的数据;当Provider的value值发生变化时,它内部的所有消费组件都会重新渲染
<UserContext.Provider value={{nickname: "kobe", age: 30}}><ThemeContext.Provider value={{color: "red", size: "30"}}>
<Home {...info}/></ThemeContext.Provider>
</UserContext.Provider>
  1. Class.contextType
    • 挂裁在class 上的contextType属性会被重赋值为一个ReactcreateContext()创建的Context对象,能使用this.context来消费最近Context 上的那个值
HomeInfo.contextType = ThemeContext
  1. Context.Consumer
    • 使用:当使用value的组件是一个函数式组件时;当组件中需要使用多个Context时
export class HomeInfo extends Component {render() {return (<div><h2>HomeInfo: {this.context.color}</h2><UserContext.Consumer>{value => {return <h2>Info User: {value.nickname}</h2>}}</UserContext.Consumer></div>)}
}
  • 全局事件总线event-bus,eventBus.emit,eventBus.on,eventBus.off

setState原理

  • setState方法是从Component中继承过来的监听数据变化的方法
  • setState的三种写法:
changeText() {// 1.setState基本使用this.setState({message: "你好啊, 李银河"})// 2.setState可以传入一个回调函数// 好处一: 可以在回调函数中编写新的state的逻辑// 好处二: 当前的回调函数会将之前的state和props传递进来this.setState((state, props) => {// 1.编写一些对新的state处理逻辑// 2.可以获取之前的state和props值console.log(this.state.message, this.props)return {message: "你好啊, 李银河"}})// 3.setState在React的事件处理中是一个异步调用// 如果希望在数据更新之后(数据合并), 获取到对应的结果执行一些逻辑代码// 那么可以在setState中传入第二个参数: callbackthis.setState({ message: "你好啊, 李银河" }, () => {console.log("++++++:", this.state.message)})console.log("------:", this.state.message)}
  • setState更新是异步的,可以显著的提升性能
    • 如果每次调用setState都进行一次更新,那么意味着render函数会被频繁调用,界面重新渲染,这样效率是很低的;最好的办法应该是获取到多个更新,之后进行批量更新
  • 如果同步更新了state,但是还没有执行render函数,那么state和props不能保持同步
    • state和props不能保持—致性,会在开发中产生很多的问题

React更新机制

在这里插入图片描述

  • 发生改变时React需要基于这两颗不同的树之间的差别来判断如何有效的更新UI
  • React对这个算法进行了优化,将其优化成了O(n):
    • 同层节点之间相互比较,不会跨节点比较;
    • 不同类型的节点,产生不同的树结构;
    • 开发中,可以通过key来指定哪些节点在不同的渲染下保持稳定
  • shouldComponentUpdate
    • 该方法有两个参数:
      • 参数一: nextProps修改之后,最新的props属性
      • 参数二: nextState修改之后,最新的state属性
    • 该方法返回值是一个boolean类型:
      • 返回值为true,那么就需要调用render方法
      • 返回值为false,那么就不需要调用render方法
      • 默认返回的是true,也就是只要state发生改变,就会调用render方法;
  • shouldComponentUpdate -> PureComponent(类组件,内部自动对状态进行判断)
    • memo(函数组件);const Profile = memo(function(props) {}

使用ref

  1. 传入字符串
  • 使用时通过this.refs.传入的字符串格式获取对应的元素
  1. 传入一个对象
  • 对象是通过React.createRef()方式创建出来的;使用时获取到创建的对象其中有一个current属性就是对应的元素;
  1. 传入一个函数
  • 该函数会在DOM被挂载时进行回调,这个函数会传入一个元素对象,我们可以自己保存;使用时,直接拿到之前保存的元素对象即可
export class App extends PureComponent {constructor() {super()this.state = {}this.titleRef = createRef()this.titleEl = null}getNativeDOM() {// 1.方式一: 在React元素上绑定一个ref字符串console.log(this.refs.why)// 2.方式二: 提前创建好ref对象, createRef(), 将创建出来的对象绑定到元素console.log(this.titleRef.current)// 3.方式三: 传入一个回调函数, 在对应的元素被渲染之后, 回调函数被执行, 并且将元素传入console.log(this.titleEl)}render() {return (<div><h2 ref="why">Hello World</h2><h2 ref={this.titleRef}>你好啊,李银河</h2><h2 ref={el => this.titleEl = el}>你好啊, 师姐</h2><button onClick={e => this.getNativeDOM()}>获取DOM</button></div>)}
}
  • ref 的值根据节点的类型而有所不同:
    • 当ref属性用于HTML元素时,构造函数中使用React.createRef()创建的 ref 接收底层DOM元素作为其current属性
    • 当ref属性用于自定义 class组件时,ref对象接收组件的挂载实例作为其current属性
    • 不能在函数组件上使用ref 属性,因为他们没有实例,使用React.forwardRef
      • const HelloWorld = forwardRef(function(props, ref) {}

受控/非受控组件

受控组件

  • 在React中,可变状态(mutable state)通常保存在组件的state属性中,并且只能通过使用setState()来更新
    • 我们将两者结合起来,使React的state成为“唯—数据源”
    • 渲染表单的React 组件还控制着用户输入过程中表单发生的操作
    • 被React 以这种方式控制取值的表单输入元素就叫做“受控组件
  • 基础:
export class App extends PureComponent {constructor() {super()this.state = {username: "coderwhy"}}inputChange(event) {console.log("inputChange:", event.target.value)this.setState({ username: event.target.value })}render() {const { username } = this.statereturn (<div>{/* 受控组件 */}<input type="checkbox" value={username} onChange={e => this.inputChange(e)}/>{/* 非受控组件 */}<input type="text" /><h2>username: {username}</h2></div>)}
}
  • 进阶
export class App extends PureComponent {constructor() {super()this.state = {username: "",password: "",isAgree: false,hobbies: [{ value: "sing", text: "唱", isChecked: false },{ value: "dance", text: "跳", isChecked: false },{ value: "rap", text: "rap", isChecked: false }],fruit: ["orange"]}}handleSubmitClick(event) {// 1.阻止默认的行为event.preventDefault()// 2.获取到所有的表单数据, 对数据进行处理console.log("获取所有的输入内容")console.log(this.state.username, this.state.password)const hobbies = this.state.hobbies.filter(item => item.isChecked).map(item => item.value)console.log("获取爱好: ", hobbies)// 3.以网络请求的方式, 将数据传递给服务器(ajax/fetch/axios)}handleInputChange(event) {this.setState({[event.target.name]: event.target.value})}handleAgreeChange(event) {this.setState({ isAgree: event.target.checked })}handleHobbiesChange(event, index) {const hobbies = [...this.state.hobbies]hobbies[index].isChecked = event.target.checkedthis.setState({ hobbies })}handleFruitChange(event) {const options = Array.from(event.target.selectedOptions)const values = options.map(item => item.value)this.setState({ fruit: values })// 额外补充: Array.from(可迭代对象)// Array.from(arguments)const values2 = Array.from(event.target.selectedOptions, item => item.value)console.log(values2)}render() {const { username, password, isAgree, hobbies, fruit } = this.statereturn (<div><form onSubmit={e => this.handleSubmitClick(e)}>{/* 1.用户名和密码 */}<div><label htmlFor="username">用户: <input id='username' type="text" name='username' value={username} onChange={e => this.handleInputChange(e)}/></label><label htmlFor="password">密码: <input id='password' type="password" name='password' value={password} onChange={e => this.handleInputChange(e)}/></label></div>{/* 2.checkbox单选 */}<label htmlFor="agree"><input id='agree' type="checkbox" checked={isAgree} onChange={e => this.handleAgreeChange(e)}/>同意协议</label>{/* 3.checkbox多选 */}<div>您的爱好:{hobbies.map((item, index) => {return (<label htmlFor={item.value} key={item.value}><input type="checkbox"id={item.value} checked={item.isChecked}onChange={e => this.handleHobbiesChange(e, index)}/><span>{item.text}</span></label>)})}</div>{/* 4.select */}<select value={fruit} onChange={e => this.handleFruitChange(e)} multiple><option value="apple">苹果</option><option value="orange">橘子</option><option value="banana">香蕉</option></select><div><button type='submit'>注册</button></div></form></div>)}
}

非受控组件

  • 使用非受控组件,表单数据交由DOM节点来处理,使用ref来获取,使用defaultValue来设置默认值

高阶函数

  • 满足以下条件之一:接受一个或多个函数做为输入,输出一个函数
  • 高阶组件(HOC)官方定义:高阶组件是参数为组件,返回值为新组件的函数
// 定义一个高阶组件
function hoc(Cpn) {// 1.定义类组件class NewCpn extends PureComponent {render() {return <Cpn name="why"/>}}return NewCpn// 定义函数组件// function NewCpn2(props) {// }// return NewCpn2
}class HelloWorld extends PureComponent {render() {return <h1>Hello World</h1>}
}const HelloWorldHOC = hoc(HelloWorld)export class App extends PureComponent {render() {return (<div><HelloWorldHOC/></div>)}
}
  • 应用:装饰器模式,用于增强现有组件的功能
  1. props的增强–给一些需要特殊数据的组件, 注入props
  2. 利用高阶组件来共享Context
  3. 渲染判断鉴权
  4. 生命周期劫持
  • 早期的React有提供组件之间的一种复用方式是mixin,目前已经不再建议使用:

    • Mixin可能会相互依赖,相互耦合,不利于代码维护
    • 不同的Mixin中的方法可能会相互冲突
    • Mixin非常多时,组件处理起来会比较麻烦,甚至还要为其做相关处理,这样会给代码造成滚雪球式的复杂性
  • HOC也有自己的一些缺陷:

    • HOC需要在原组件上进行包裹或者嵌套,如果大量使用HOC,将会产生非常多的嵌套,这让调试变得非常困难
    • HOC可以劫持props,在不遵守约定的情况下也可能造成冲突

Portals/fragment/StrictMode

  • Portal(类似Vue3中Teleport)提供了一种将子节点渲染到存在于父组件以外的DOM节点的优秀的方案:
    • 第一个参数(child)是任何可渲染的React子元素,例如一个元素,字符串或fragment
    • 第二个参数(container)是一个DOM元素

{createPortal(<h2>App H2</h2>, document.querySelector("#why")) }

  • 我们希望可以不渲染这样一个div则使用Fragment(类似Vue中的telemplate)
    • Fragment 允许将子列表分组,而无需向DOM添加额外节点
    • 如果我们需要在Fragment中添加key,那么就不能使用短语法<></>
<Fragment><h2>{item.title}</h2><p>{item.content}</p>
</Fragment>
  • StrictMode是一个用来突出显示应用程序中潜在问题的工具:
    • 与Fragment一样,StrictMode不会渲染任何可见的Ul
    • 它为其后代元素触发额外的检查和警告;
    • 严格模式检查仅在开发模式下运行;它们不会影响生产构建
<StrictMode><Home/>
</StrictMode>
  1. 识别不安全的生命周期
  2. 使用过时的ref APl
  3. 检查意外的副作用
    • 这个组件的constructor会被调用两次
    • 这是严格模式下故意进行的操作,让你来查看在这里写的一些逻辑代码被调用多次时,是否会产生一些副作用
    • 在生产环境中,是不会被调用两次的
  4. 使用废弃的findDOMNode方法
    • 在之前的React API中,可以通过findDOMNode来获取DOM,不过已经不推荐使用了
  5. 检测过时的context APl
    • 早期的Context是通过static属性声明Context对象属性,通过getChildContext返回Context对象等方式来使用Context的

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

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

相关文章

《游戏引擎架构》--学习3

内存管理 优化动态内存分配 维持最低限度的堆分配&#xff0c;并且永不在紧凑循环中使用堆分配 容器 迭代器 Unicode

TCP 三次握手和四次挥手

为了准确无误地把数据送达目标处&#xff0c;TCP协议采用了三次握手策略。 1 TCP 三次握手漫画图解 如下图所示&#xff0c;下面的两个机器人通过3次握手确定了对方能正确接收和发送消息(图片来源网络)。 简单示意图&#xff1a; 客户端–发送带有 SYN 标志的数据包–一次握手…

数据库管理-第153期 Oracle Vector DB AI-05(20240221)

数据库管理153期 2024-02-21 数据库管理-第153期 Oracle Vector DB & AI-05&#xff08;20240221&#xff09;1 Oracle Vector的其他特性示例1&#xff1a;示例2 2 简单使用Oracle Vector环境创建包含Vector数据类型的表插入向量数据 总结 数据库管理-第153期 Oracle Vecto…

采用SSI技术的FPGA器件

9个关于SSI芯片的必知问题-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1530543

无人机快递(物流)技术方案,无人机快递(物流)基础知识

无人机快递技术是一种利用无人机进行快递配送的先进技术。通过利用无人机&#xff0c;快递企业能够在偏远地区或难以通行的地区提供配送服务&#xff0c;同时提高配送效率并降低人力成本。 无人机基本情况 无人驾驶飞机简称“无人机”&#xff0c;是利用无线电遥控设备和自备的…

使用 JMeter 生成测试数据对 MySQL 进行压力测试

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

离散数学(一) 集合

属于关系 表示 枚举法; 叙述法; 文氏图法 基数 空集 全集 全集是相对唯一的

还在为选择办公软件而烦恼吗?不妨试试ONLYofficeV8.0

目录 一.优势一DOC 1.丰富的文字处理功能 2.按用户既定的规则编辑 3.使用AI助手 4.保持创意 5.深入分析文本 6.改善团队工作流程 7.轻松对比文档 8.扩展编辑功能 二.优势二sheet 1.数据分析 2.轻松实现精准计算 3.轻松分析数据 4.可视化呈现数据 5.增强团队协作…

反转链表.

题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例 解题方法 假设链表为 1→2→3→∅&#xff0c;我们想要把它改成∅←1←2←3。在遍历链表时&#xff0c;将当前节点的 next指针改为指向前一个节点。由于节点没有引用其前一…

写给正在迷茫的你:4年程序员职业生涯感悟

前言 最近有许多小伙伴找我来咨询Python&#xff0c;我来讲几个极其重要&#xff0c;但是大多数Python小白都在一直犯的思维错误吧&#xff01;如果你能早点了解清楚这些&#xff0c;会改变你的编程学习生涯的。小编这一期专门总结了大家问的最多的&#xff0c;关于学习Python…

pytest基本应用

文章目录 1.pytest安装2.用例运行规则3.常用参数断言运行参数用例控制setup和teardownini配置文件 4.常用插件5.pytest高阶用法用例跳过参数化 6.pytest之Fixture使用fixture使用装饰器usefixtures 7.pytest之conftest.py8.conftestfixtureyieldyield介绍前后置使用 1.pytest安…

GZ036 区块链技术应用赛项赛题第9套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;9卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 随着异地务工人员的增多&#xff0c;房屋租赁成为一个广阔是市场&#xff1b;目前&#xff0c;现有技术中的房屋租赁是由…

centos7部署nfs+keepalived+drbd

一、项目需求描述 现在使用的架构是nfskeepalivedrsyncsersync&#xff0c;目前这套架构存在主从nfs节点数据同步不一致问题&#xff0c;大概会有 120s左右的数据延长同步时间&#xff0c;需要提供优化的自动化方案。 二、现有方案缺点 1、切换不能保证主从节点数据一致。 2、…

四、分类算法 - 随机森林

目录 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结 sklearn转换器和估算器KNN算法模型选择和调优朴素贝叶斯算法决策树随机森林 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结

【论文阅读】【yolo系列】YOLO-Pose的论文阅读

Abstract 我们介绍YOLO-pose&#xff0c;一种无热图联合检测的新方法&#xff0c;基于流行的YOLO目标检测框架的图像二维多人姿态估计。 【现有方法的问题】现有的基于热图的两阶段方法是次优的&#xff0c;因为它们不是端到端可训练的&#xff0c;训练依赖于surrogate L1 loss…

12 Autosar_SWS_MemoryMapping.pdf解读

AUTOSAR中MemMap_autosar memmap-CSDN博客 1、Memory Map的作用 1.1 避免RAM的浪费&#xff1a;不同类型的变量&#xff0c;为了对齐造成的空间两份&#xff1b; 1.2 特殊RAM的用途&#xff1a;比如一些变量通过位掩码来获取&#xff0c;如果map到特定RAM可以通过编译器的位掩码…

爬取链家二手房房价数据存入mongodb并进行分析

实验目的 1.使用python将爬虫数据存入mongodb&#xff1b; 2.使用python读取mongodb数据并进行可视化分析。 实验原理 MongoDB是文档数据库&#xff0c;采用BSON的结构来存储数据。在文档中可嵌套其他文档类型&#xff0c;使得MongoDB具有很强的数据描述能力。本节案例使用的…

IP地址定位可以精确到哪里

IP地址定位能够精确到的位置级别取决于多种因素&#xff0c;包括IP地址的分配方式、数据库的质量和更新频率、用户的移动性等。一般而言&#xff0c;IP地址定位可以精确到市级&#xff0c;甚至可以达到街道级别 https://www.ip66.net/?utm-sourceLJ&utm-keyword?1146 但需…

大数据在电商领域的典型应用

大数据作为一种新兴的信息技术&#xff0c;是无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 大数据技术是指在数据获取、存储、管理、…

程序媛的mac修炼手册-- 如何彻底卸载Python

啊&#xff0c;前段时间因为想尝试chatgpt的API&#xff0c;需要先创建一个python虚拟环境来安装OpenAI Python library. 结果&#xff0c;不出意外的出意外了&#xff0c;安装好OpenAI Python library后&#xff0c;因为身份认证问题&#xff0c;根本就没有获取API key的权限…