React系统学习3(組件三大核心属性之props)
Posted 程序员涂小哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React系统学习3(組件三大核心属性之props)相关的知识,希望对你有一定的参考价值。
从一个小需求出发
假设有这样一个需求,需要在页面中输出不同水果的一些信息,例如id编号、名称和价格。
很显然,上边有三种不同的水果,但是每一种的格式是一模一样的,看起来就是ul
和li
。
那么根据之前的学习,可以先定义出类似这样的组件以及相关代码,先实现其中一个:
<body>
<div id="test"></div>
<!--核心库-->
<script type="text/javascript" src="../../js/react.development.js"></script>
<!--操作dom-->
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<!--用户将jsx转为js-->
<script type="text/javascript" src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Order extends React.Component
render()
return (
<ul>
<li>id:1</li>
<li>name:苹果</li>
<li>price:6.8元</li>
</ul>
)
ReactDOM.render(<Order/>,document.getElementById('test'))
</script>
</body>
上边已经实现出来了一种水果的信息展示,如果要三个都出来,需要怎么办呢?实现方式不止一种,例如最简单粗暴的就可以直接在组件里写三个ul
。
但是很显然这样存在一些问题,其中一个问题就是这样的数据是写死的,而实际上这些数据不应该是固定的,例如价格。
另一个问题就是,真的写多个ul
的话,明显是不符合组件的思想的,组件本身就是为了复用,如果写成这样子,那就完全体现不出来组件的意义。
那么下边就来解决这两个问题。
数据处理
由于之前学过了state
,所以第一时间就能想到把数据从固定变为不固定,可以用state
试试,于是组件的定义改成了如下这样:
class Order extends React.Component
state = id:1,name:'苹果',price:6.8
render()
return (
<ul>
<li>id:this.state.id</li>
<li>name:this.state.name</li>
<li>price:this.state.price元</li>
</ul>
)
看起来,数据好像不是固定的了,因为state里边数据可以通过构造方法等初始化方式获得,还可以通过事件回调进行修改。
但是这里依然只是一个水果,要继续实现三个水果的展示又要怎么办呢?
首先,可能会先把代码写成这样:
<body>
<div id="test"></div>
<div id="test1"></div>
<div id="test2"></div>
<!--核心库-->
<script type="text/javascript" src="../../js/react.development.js"></script>
<!--操作dom-->
<script type="text/javascript" src="../../js/react-dom.development.js"></script>
<!--用户将jsx转为js-->
<script type="text/javascript" src="https://cdn.staticfile.org/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Order extends React.Component
state = id:1,name:'苹果',price:6.8
render()
return (
<ul>
<li>id:this.state.id</li>
<li>name:this.state.name</li>
<li>price:this.state.price元</li>
</ul>
)
ReactDOM.render(<Order/>,document.getElementById('test'))
ReactDOM.render(<Order/>,document.getElementById('test1'))
ReactDOM.render(<Order/>,document.getElementById('test2'))
</script>
</body>
上边代码看起来展示了三种水果,也实现了组件的复用,但是实际上展示效果是这样的:
这并不是展示了三种水果,而是一个水果展示了三次。
如何解决这个问题呢?这就需要今天的主角props
上场了。
props基本用法
props
和state
一样是react
内置的属性之一,props可以理解为就是组件标签的属性集合,会帮我们收集组件中所有属性。
使用props
可以很好的解决上边的问题,修改后的组件定义以及使用的基本代码如下:
class Order extends React.Component
render()
return (
<ul>
<li>id:this.props.id</li>
<li>name:this.props.name</li>
<li>price:this.props.price元</li>
</ul>
)
ReactDOM.render(<Order id=1 name='苹果' price=6.8/>,document.getElementById('test'))
ReactDOM.render(<Order id=2 name='香蕉' price=3.7/>,document.getElementById('test1'))
ReactDOM.render(<Order id=3 name='梨子' price=4.5/>,document.getElementById('test2'))
进行上边这样的修改后,刷新页面就可以看到结果是最开头想要的效果了,如下:
对象解构
虽然效果是实现了,但是上边代码却显得比较繁琐,示例中仅仅展示了三个属性,而真实开发中经常会十几甚至几十的属性,那么像上边这样的代码就会显得极其难看。
上边代码是可以优化的,其中一个就是对象解构,例如组件定义中使用属性时如果使用解构写法,就可以改成下边这样:
render()
const id,name,price =this.props;
return (
<ul>
<li>id:id</li>
<li>name:name</li>
<li>price:price元</li>
</ul>
)
解构相当于就是把一个对象的属性一个个拿出来,然后赋值给新的变量,这样之后使用的时候直接使用对应的变量就可以了,而不需要每次都从原对象中拿,代码看起来就会简洁很多。
三点展开运算符传值
除了组件中使用数据可以用解构来优化代码外,组件使用时的代码也是可以优化的。
上边的代码中,三个属性是分别传递的,当属性特别多的时候就特别难写,也特别难看。
同时,实际开发的时候一般这种数据也是从后端返回,基本也都是对象的方式,而不是直接一个一个属性的返回。
因此在使用组件并传数据的时候,上边的代码可以进一步优化为下边这样:
//模拟数据
let fruit=id:1,name:'苹果',price:6.8
let fruit1=id:2,name:'香蕉',price:3.7
let fruit2=id:3,name:'梨子',price:4.5
ReactDOM.render(<Order ...fruit/>,document.getElementById('test'))
ReactDOM.render(<Order ...fruit1/>,document.getElementById('test1'))
ReactDOM.render(<Order ...fruit2/>,document.getElementById('test2'))
当然了,真正开发时要怎么写,还要看具体的需求,如果本身就只需要其中几个属性,那么自然也可以直接传值。
数据约束及默认值
上边代码实现了一开始的需求,最做了一定的优化,但是还是不够完善,因为实际开发的时候,经常需要对数据进行约束,例如数据的类型限定,例如是否必传,例如没有数据的时候是否需要默认值等等。
针对上边的代码,如果要加上这些限制,可以改成这样:
class Order extends React.Component
render()
const id,name,price =this.props;
return (
<ul>
<li>id:id</li>
<li>name:name</li>
<li>price:price元</li>
</ul>
)
Order.propTypes=
id:PropTypes.number.isRequired,
name:PropTypes.string
Order.defaultProps=
price:0
let fruit=id:1,name:'苹果',price:6.8
let fruit1=id:2,name:'香蕉',price:3.7
let fruit2=id:3,name:'梨子'
ReactDOM.render(<Order ...fruit/>,document.getElementById('test'))
ReactDOM.render(<Order ...fruit1/>,document.getElementById('test1'))
ReactDOM.render(<Order ...fruit2/>,document.getElementById('test2'))
有了上边新增的Order.propTypes
和Order.defaultProps
后,就可以实现一些数据的限制以及默认值。
例如这里限制了id
必须是数字类型,并且必传;限制了name
必须是字符串类型,但是可以不传;没有对price
进行数据类型以及是否必传的限制,但是通过```Order.defaultProps`给它了默认值。
有了这些限制后,如果对应的数据不符合要求,页面也会显示,只是在控制台会有警告输出。
另外需要注意的是,这里的数字类型使用number
,字符串使用string
,如果类型是函数则需要使用func
,因为function
是关键字,所以需要替换。
还需要注意的是,PropTypes
是React
内置的类,在React15.5
之前可以直接使用React.PropTypes
,而之后的版本则需要额外引入一个依赖,例如:
<script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>
约束和默认值的优化
上边的代码还可以进一步优化,因为从定义可以看出来propTypes
和defaultProps
都是属于类的,但是却将他们定义在了类外边,就显得不那么好。
所以这两个定义是可以放到类里边的,使他们能够更清楚的显示和类的关系,修改后如下:
class Order extends React.Component
static propTypes=
id:PropTypes.number.isRequired,
name:PropTypes.string
static defaultProps=
price:0
render()
const id,name,price =this.props;
return (
<ul>
<li>id:id</li>
<li>name:name</li>
<li>price:price元</li>
</ul>
)
以上是关于React系统学习3(組件三大核心属性之props)的主要内容,如果未能解决你的问题,请参考以下文章