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

React 学习笔记2 props、refs

props

基础用法

在使用组件时,有时希望组件中展示组件定义外部的数据。

在组件上有一个props属性,在通过类式方法定义组件时,可以在渲染组件时,在组件标签上添加属性,这个属性会以key value的形式放入props。

<body><div id="demo"></div><script src="https://unpkg.com/react@17/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script><!-- Don't use this in production: --><script src="https://unpkg.com/@babel/standalone/babel.min.js"></script><script type="text/babel">class Cat extends React.Component {render() {return <h2>{this.props.name}--{this.props.color}</h2>}}ReactDOM.render(<Cat name="cat" color="orange"/>, document.getElementById('demo'))</script>
</body>

props批量传递

当这种传参方式也存在问题,一个问题是,当需要传入的参数过多时,很难每个都手写。一个解决办法是使用...语法:

实际上,对于对象类型来说,...展开运算符是无法直接应用在对象上的,但如果使用{...对象}的形式是可以的,相当于是在构造字面量对象时使用展开语法,相当于克隆了对象,而且是深拷贝。通过{...对象,要修改的value对应的key:新value}来进行修改,会对这些同名key进行合并。

而在React的标签中,书写{...对象}时,外部的{}并不是字面量克隆,而是表示内部的语法是JS表达式,相当于...对象,这是React内部允许的特殊写法,通过React+Babel,支持使用...对对象进行展开。但这种语法并不是在任意位置都会生效,这种语法仅仅适用于标签参数的传递。

    <script type="text/babel">class Cat extends React.Component {render() {return <h2>{this.props.name}--{this.props.color}</h2>}}const data = {name:'cat',color:"orange",age:10}ReactDOM.render(<Cat {...data}/>, document.getElementById('demo'))</script>

限制props

通过属性传递key value时,value默认是字符串,如果需要在标签中传递数字,需要通过key={数字}的形式来进行,但可能代码是很多人书写的,有时候其他人并不会考虑后续使用的各种情况,这会导致代码产生各种各样的问题。如果希望传递的属性是某个固定的数值,就需要对props添加限制。

React支持对props的 数据类型、数据默认值、数据是否必须传递 进行限制。

这要通过给组件添加propTypes属性来实现。

propTypes的value是一个对象,通过在对象里添加配置,React可以给props添加限制。

通过key:PropTypes.需要传递的类型(小写)的形式可以对props的类型进行限制。通过.isRequired可以设置属性为必填项。通过对类加上defaultProps可以为属性设置默认值,defaultProps的value为对象,对象内部以key:默认值的形式进行设置。通过标签也能传递函数,函数的数据类型是func。

propTypes是需要限制props时,应该给类式组件添加的属性,而PropTypes是支持设置限制的方法,两者并不相同。

PropTypes并不是React内置的方法,需要npm install prop-types及import PropTypes from 'prop-types'来引入PropTypes。

npm install prop-typesimport PropTypes from 'prop-types'

而对于直接在HTML文件中编写的React Demo,可以通过js的方式进行引入:

<script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script>

<body><div id="demo"></div><script src="https://unpkg.com/react@17/umd/react.development.js"></script><script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script><script src="https://unpkg.com/@babel/standalone/babel.min.js"></script><script src="https://unpkg.com/prop-types@15.6/prop-types.js"></script><script type="text/babel">class Cat extends React.Component {render() {return <h2>{this.props.name}--{this.props.color}--{this.props.say()}</h2>}}Cat.propTypes = {name: PropTypes.string.isRequired,age: PropTypes.number,say: PropTypes.func}function say(){console.log(this.name)}const data = { name: 'cat', color: "orange", age: 10 }ReactDOM.render(<Cat {...data} say={say} />, document.getElementById('demo'))</script>
</body>

props是只读的,通过props传递的参数,在类内部是无法修改的。

props简写形式

组件类.propTypes和组件类.defaultProps可以不在类外面编写,可以直接在类内部定义:

    <script type="text/babel">class Cat extends React.Component {static propTypes = {name: PropTypes.string.isRequired,age: PropTypes.number,say: PropTypes.func}static defaultProps = {color: 'black'}render() {return <h2>{this.props.name}--{this.props.color}--{this.props.say()}</h2>}}function say() {console.log(this.name)}const data = { name: 'cat', age: 10 }ReactDOM.render(<Cat {...data} say={say} />, document.getElementById('demo'))</script>

构造器中的props

在通过构造器对属性进行操作时,构造器会有一个参数props,且在构造器内部需要super(props)。

为什么需要在构造器中编写props相关的代码呢?这是为了防止this.props调用时出现属性未定义的BUG。

类中构造器其实也可以不写props,也不会报错,但此时通过this.props访问得到的是undefined。如果不需要访问this.props,也可以完全不写props和super(props)。

函数式组件的props

对于函数式组件,虽然函数式组件中没有this,也没有state(可以通过hooks间接实现)和refs,但是函数式组件中有Props。

使用函数式组件时,用法和类式类似,也是在标签中编写要传递的数据,在函数中,通过参数props获得传递的数据。

函数式组件也可以对props进行限制,语法和类式组件类似,只不过函数式组件对props的限制只能写在函数外面。

    <script type="text/babel">function Cat(props) {return <h2>{props.name}--{props.color}--{props.say()}</h2>}Cat.propTypes = {name: PropTypes.string.isRequired,age: PropTypes.number,say: PropTypes.func}Cat.defaultProps = {color: 'black'}function say() {console.log(this.name)}const data = { name: 'cat', age: 10 }ReactDOM.render(<Cat {...data} say={say} />, document.getElementById('demo'))</script>

refs

ref的value有三种形式:

字符串形式

ref是React中提供的一个属性,给标签加入ref属性后,组件实例上的refs对象中会出现这个ref,refs中的key是标签中给ref设定的value,refs对应的value是ref属性所在的标签。设置好ref后,通过this.refs.给ref设定的value,可以获取ref所在的标签。

通过refs获取的是真实DOM节点。

这种方式不被React推荐,在之后的版本中可能会被移除。字符串类型的ref存在效率问题。

    <script type="text/babel">class Cat extends React.Component {alertData=()=>{const nowDOM = this.refs.inputData;alert(nowDOM.value)}render(){return (<div><input ref="inputData"/><button onClick={this.alertData}>click</button></div>)}}const data = { name: 'cat', age: 10 }ReactDOM.render(<Cat />, document.getElementById('demo'))</script>

回调函数形式

ref的value,也可以是一个回调函数。由于函数是JS表达式,需要包裹在{}中,这个回调函数的参数是ref属性所处的DOM,在函数体中,一般把这个属性放在组件实例上。

    <script type="text/babel">class Cat extends React.Component {alertData=()=>{const nowDOM = this.inputDOMalert(nowDOM.value)}render(){return (<div><input ref={ (currentDOM)=>{this.inputDOM = currentDOM} }/><button onClick={this.alertData}>click</button></div>)}}ReactDOM.render(<Cat />, document.getElementById('demo'))</script>

回调函数在什么时候被调用呢?实际上,在初始时,这个回调函数会被调用一次。除此之外,如果ref是以内联函数形式定义的,在更新时(初始化加载时不是更新,更新是初始化之后,数据改变引起的更新)回调函数会被执行两次,第一次参数是null,第二次参数才是ref所在的DOM元素。这是因为在每次渲染时会创建一个新的函数实例,React在更新时,会清空旧的ref并设置新的。

    <script type="text/babel">class Cat extends React.Component {alertData=()=>{const nowDOM = this.inputDOMalert(nowDOM.value)}state={flag:true,}changeFlag=()=>{const flag = this.state.flagthis.setState( {flag : !flag})}render(){return (<div><input ref={ (currentDOM)=>{this.inputDOM = currentDOM;console.log(currentDOM)} }/><button onClick={this.alertData}>click</button><button onClick={this.changeFlag}>change</button><h2>{this.state.flag ? 'cat':'dog'}</h2></div>)}}ReactDOM.render(<Cat />, document.getElementById('demo'))</script>

但这种情况一般并不会影响ref的功能,仅仅是会多调用一次。如果还是想避免这种情况,可以不使用内联函数,而是使用类内部绑定的函数。

    <script type="text/babel">class Cat extends React.Component {alertData = () => {const nowDOM = this.inputDOMalert(nowDOM.value)}state = {flag: true,}changeFlag = () => {const flag = this.state.flagthis.setState({flag: !flag})}getInputDOM = (currentDOM) => {this.inputDOM = currentDOMconsole.log(currentDOM)}render() {return (<div><input ref={this.getInputDOM} /><button onClick={this.alertData}>click</button><button onClick={this.changeFlag}>change</button><h2>{this.state.flag ? 'cat' : 'dog'}</h2></div>)}}ReactDOM.render(<Cat />, document.getElementById('demo'))</script>

JSX的注释以{/* */}的形式进行。{}表示要写JS表达式,内部的/**/是JS注释。

React.createRef()

ref的value,也可以通过React.createRef()来设定。

React.createRef是一个函数,调用之后会返回一个容器,可以存储被ref所标识的DOM节点。

当ref的value是createRef容器时,会把ref所在的DOM节点存储在容器中。且是存储在容器的current属性中。current中只能存储一个DOM。如果多个ref存储在一个容器中,后触发的存储会覆盖之前的。如果需要获取多个DOM,只能创建多个容器。

    <script type="text/babel">class Cat extends React.Component {alertData = () => {const nowDOM = this.inputRef.currentalert(nowDOM.value)}inputRef = React.createRef()buttonRef = React.createRef()render() {return (<div><input ref={this.inputRef} /><input ref={this.inputRef} /><button onClick={this.alertData} ref={this.buttonRef}>click</button></div>)}}ReactDOM.render(<Cat />, document.getElementById('demo'))</script>

http://www.dtcms.com/a/349404.html

相关文章:

  • 消息中间件RabbitMQ03:结合WebAPI实现点对点(P2P)推送和发布-订阅推送的Demo
  • 从C语言到数据结构:保姆级顺序表解析
  • 使用OpenSSL生成自签名证书
  • 基于PyTorch深度学习遥感影像地物分类与目标检测、分割及遥感影像问题深度学习优化
  • 逆向抄数工程师能力矩阵:设备操作(±0.05mm 精度)× 曲面重构 ×GDT 公差分析
  • C++|UDP通讯使用总结
  • Fluent Bit系列:字符集转码测试(下)
  • Dify 从入门到精通(第 55/100 篇):Dify 的模型微调(进阶篇)
  • Devops之Jenkins:Jenkins服务器中的slave节点是什么?我们为什么要使用slave节点?如何添加一个windows slave节点?
  • 如何监控ElasticSearch的集群状态?
  • Fluent Bit系列:字符集转码测试(上)
  • LengthFieldBasedFrameDecoder 详细用法
  • Error ratio tests for 200 Gb/s per lane ISLs using PMAmeasurements
  • 李沐-第十章-实现Seq2SeqAttentionDecoder时报错
  • 什么是事件循环(Event Loop)?浏览器和 Node.js 中的事件循环有什么区别?
  • springboot整合druid(多数据源配置)
  • Python_occ 学习记录 | 阵列
  • 李沐-第十章-训练Seq2SeqAttentionDecoder报错
  • 十九、云原生分布式存储 CubeFS
  • 剧本杀APP系统开发:打造多元化娱乐生态的先锋力量
  • Go编写的轻量文件监控器. 可以监控终端上指定文件夹内的变化, 阻止删除,修改,新增操作. 可以用于AWD比赛或者终端应急响应
  • TensorFlow深度学习实战(34)——TensorFlow Probability
  • GO学习记录八——多文件封装功能+redis使用
  • Node.js(2)—— Buffer
  • 安卓Android低功耗蓝牙BLE连接异常报错133
  • Docker Compose 部署 Elasticsearch 8.12.2 集成 IK 中文分词器完整指南
  • Go初级三
  • 上海AI实验室突破扩散模型!GetMesh融合点云与三平面,重塑3D内容创作
  • 少儿舞蹈小程序需求规格说明书
  • AutoCAD Electrical缺少驱动程序“AceRedist“解决方法