React系统学习3(組件三大核心属性之props)

Posted 程序员涂小哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React系统学习3(組件三大核心属性之props)相关的知识,希望对你有一定的参考价值。

从一个小需求出发

假设有这样一个需求,需要在页面中输出不同水果的一些信息,例如id编号、名称和价格。

很显然,上边有三种不同的水果,但是每一种的格式是一模一样的,看起来就是ulli

那么根据之前的学习,可以先定义出类似这样的组件以及相关代码,先实现其中一个:

<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基本用法

propsstate一样是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.propTypesOrder.defaultProps后,就可以实现一些数据的限制以及默认值。

例如这里限制了id必须是数字类型,并且必传;限制了name必须是字符串类型,但是可以不传;没有对price进行数据类型以及是否必传的限制,但是通过```Order.defaultProps`给它了默认值。

有了这些限制后,如果对应的数据不符合要求,页面也会显示,只是在控制台会有警告输出。

另外需要注意的是,这里的数字类型使用number,字符串使用string,如果类型是函数则需要使用func,因为function是关键字,所以需要替换。

还需要注意的是,PropTypesReact内置的类,在React15.5之前可以直接使用React.PropTypes,而之后的版本则需要额外引入一个依赖,例如:

<script type="text/javascript" src="https://cdn.bootcss.com/prop-types/15.6.1/prop-types.js"></script>

约束和默认值的优化

上边的代码还可以进一步优化,因为从定义可以看出来propTypesdefaultProps都是属于类的,但是却将他们定义在了类外边,就显得不那么好。

所以这两个定义是可以放到类里边的,使他们能够更清楚的显示和类的关系,修改后如下:

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)的主要内容,如果未能解决你的问题,请参考以下文章

React系统学习3(組件三大核心属性之props)

React系统学习3(組件三大核心属性之props)

React系统学习4(組件三大核心属性之refs)

React系统学习4(組件三大核心属性之refs)

React系统学习4(組件三大核心属性之refs)

React系统学习4(組件三大核心属性之refs)