一. 调试工具的安装及使用
React在浏览器端是有一个调试工具的,这就是React developer tools,它会比console.log()方便很多。
1.1 React developer tools的三种状态
React developer tools有三种颜色,三种颜色代表三种状态:
- 灰色:说明页面不是由React编写的,不可使用该插件。
- 黑色: 说明页面是用React编写的,并且处于生产(production)环境当中。
- 红色: 说明页面是用React编写的,并且处于调试开发环境当中。
1.2 React developer tools使用
打开浏览器,然后按F12,打开开发者工具,然后在面板中你会找到这个安装的插件了。
在这里你可以清晰的看到React的结构,让自己写的代码更加清晰,你还可以看到组件间的数据传递,再也不用写console.log来测试程序了。
二. PropTypes校验传递值
在父组件向子组件传递数据时,使用了属性的方式,也就是props,但“小姐姐服务菜单”的案例并没有任何的限制。这在工作中是完全不允许的,因为大型项目,如果你不校验,后期会变的异常混乱,业务逻辑也没办法保证。
2.1 PropTypes的简单应用
我们在Xiaojiejie.js
组件里传递了4个值,有字符串,有数字,有方法,这些都是可以使用PropTypes限制的。在使用前需要先引入PropTypes
。
import PropTypes from 'prop-types'
引入后,就可以在组件的下方进行引用了,需要注意的是子组件的最下面(不是类里边),写入下面的代码:
import React, { Component } from 'react'; //imrc
import PropTypes from 'prop-types'
class XiaojiejieItem extends Component { //cc
constructor(props){
super(props)
this.handleClick=this.handleClick.bind(this)
}
render() {
return (
<div onClick={this.handleClick}>
{this.props.content}
</div>
);
}
handleClick(){
this.props.deleteItem(this.props.index)
}
}
//--------------类型校验代码--------start
XiaojiejieItem.propTypes={
content:PropTypes.string,
deleteItem:PropTypes.func,
index:PropTypes.number
}
//--------------类型校验代码--------end
export default XiaojiejieItem;
这时候你在浏览器中查看效果,是什么都看不出来的,你需要修改一个错误的校验。比如我们把index改为必须是字符串。
index:PorpTypes.string
这时候浏览器的console里就会报错了,报错信息如下:
Warning: Failed prop type: Invalid prop `index` of type `number` supplied to `XiaojiejieItem`, expected `string`.
in XiaojiejieItem (at Xiaojiejie.js:28)
in Xiaojiejie (at src/index.js:5)
意思就是要求传递字符串,而我们却传递了数字过去,所以给了警告。
2.2 必传值的校验
比如现在我们加入一个avname
的属性,并放入JSX
中,就算不传递这个值也不会报错的。代码如下:
render() {
return (
<div onClick={this.handleClick}>
{this.props.avname}为你做- {this.props.content}
</div>
);
}
这时候代码是不会报错的,我们传不传无所谓。比如我们现在传一个属性过来。
<ul>
{
this.state.list.map((item,index)=>{
return (
<XiaojiejieItem
key={index+item}
content={item}
index={index}
avname='波多野结衣'
deleteItem={this.deleteItem.bind(this)}
/>
)
})
}
</ul>
这时候页面显示正常了,但是怎样避免必须传递avname这个属性值?如果不传递就报错,这就需要使用isRequired关键字了,它表示必须进行传递,如果不传递就报错。
avname:PropTypes.string.isRequired
2.3 使用默认值defaultProps
有些人是非常腼腆的,他是不好意思选择的,所以有时候是需要有一个默认的人为她服务的。defalutProps就可以实现默认值的功能,比如现在把avname的默认值设置成"松岛枫" ,然后把avname的属性删除掉。
XiaojiejieItem.defaultProps = {
avname:'松岛枫'
}
其实检测的类型非常多,你最好去官方文档看一下,能得到比较全面的了解。
上述整体代码如下:
import React from 'react';
import PropTypes from 'prop-types'
import {Fragment} from 'react'
class XiaojiejieItem extends React.Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
render() {
return (
<Fragment>
<div>{this.props.avname}</div>
<li onClick={this.handleClick}>{this.props.content}</li>
</Fragment>
);
}
handleClick() {
console.log(this.props.index)
this.props.delItem(this.props.index)
}
}
XiaojiejieItem.propTypes = {
content: PropTypes.string.isRequired,
index: PropTypes.number,
delItem: PropTypes.func
}
XiaojiejieItem.defaultProps = {
avname: '哈哈哈'
}
export default XiaojiejieItem
三. ref的使用方法
在编写组件中的方法时,经常会遇到语义化很模糊的代码,这对于团队开发是一个很大的问题。因为review代码或者合作时都会影响开发效率。或者某核心成员离开,导致项目倒闭的严重影响。所以我们必须重视react代码当中的语义化。ref是个不错的工具,快来学习一下吧。
3.1 代替原来的e.target.value
以前的案例中,我们写了下面的代码,使用了e.target,这并不直观,也不好看。这种情况我们可以使用ref来进行解决。
inputChange(e){
this.setState({
inputValue:e.target.value
})
}
如果要使用ref,需要先在JSX中进行绑定, 绑定时最好使用ES6语法中的箭头函数,这样可以简洁明了的绑定DOM元素。
<input
id="jspang"
className="input"
value={this.state.inputValue}
onChange={this.inputChange.bind(this)}
//关键代码——----------start
ref={(input)=>{this.input=input}}
//关键代码------------end
/>
绑定后可以把上边的类改写成如下代码:
inputChange(){
this.setState({
inputValue:this.input.value
})
}
这就使我们的代码变得语义化和优雅的多。但是就我个人的经验来讲,我是不建议用ref这样操作的,因为React的是数据驱动
的,所以用ref会出现各种问题
。
3.2 this.setState
使用中的坑
比如现在我们要用ref绑定取得要服务的数量,可以先用ref进行绑定。
<ul ref={(ul)=>{this.ul=ul}}>
{
this.state.list.map((item,index)=>{
return (
<XiaojiejieItem
key={index+item}
content={item}
index={index}
deleteItem={this.deleteItem.bind(this)}
/>
)
})
}
</ul>
绑定后可以在addList()方法中,获取当前<div>的值。
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue],
inputValue:''
})
//关键代码--------------start
console.log(this.ul.querySelectorAll('div').length)
//关键代码--------------end
}
这时候你打开控制台,点击添加服务按钮,你会返现数量怎么少一个?(就是这个坑),其实这个坑是因为React中的setState是一个异步函数所造成的
。
那这个代码怎么编写才会完全正常呢?其实setState方法提供了一个回调函数,也就是它的第二个函数。下面这样写就可以实现我们想要的方法了。
addList(){
this.setState({
list:[...this.state.list,this.state.inputValue],
inputValue:''
//关键代码--------------start
},()=>{
console.log(this.ul.querySelectorAll('div').length)
})
//关键代码--------------end
}