承接上文
<body>
<div id="test1"></div>
<div id="test2"></div>
<!-- 引入核心库 -->
<script src="../js/react.development.js"></script>
<!-- 扩展库 -->
<script src="../js/react-dom.development.js"></script>
<!-- 转换jsx转为js -->
<script src="../js/babel.min.js"></script>
<script type="text/babel">
class Person extends React.Component {
render() {
console.log("this", this);
const { name, sex, age } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
);
}
}
const p = { name: "tom", sex: "男", age: 1 };
ReactDOM.render(<Person name="jerry" age="19" sex="男" />,document.getElementById("test1"));
ReactDOM.render(<Person {...p} />, document.getElementById("test2"));
</script>
</body>
现在实现一个小需求,展示的年龄比实际年龄大1岁。
比较简单,也就是对age+1
<script type="text/babel">
class Person extends React.Component {
render() {
const { name, sex, age } = this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age + 1}</li>
</ul>
);
}
}
const p = { name: "tom", sex: "男", age: 18 };
ReactDOM.render(<Person name="jerry" age="19" sex="男" />,document.getElementById("test1"));
ReactDOM.render(<Person {...p} />, document.getElementById("test2"));
</script>
打印后会发现
jerry的年龄是191,tom则是正常的19。
这是因为tom的age是Number类型,jerry的age是String类型。
这时,我们把jerry的age改成Number类型时,语法发生报错。
当我们想传递Number类型的值时,要写成{19},这是因为在js事件中才能提数据类型,才涉及到数据类型的判断
const p = { name: "tom", sex: "男", age: 18 };
ReactDOM.render(<Person name="jerry" age={19} sex="男"/>,document.getElementById("test1"));
ReactDOM.render(<Person {...p} />, document.getElementById("test2"));
这时,我们思考一个问题,{19}这种写法,是写在我们自己定义的Person组件中,
我们清晰的知道,需求上是对年龄加1,所以才这样写。但是,对于他人遇见类似需求时,并使用我们写的组件进行开发,是并不知道我们是否正确书写Number类型的传值{19},所以是有可能写下String类型的“19”,导致错误数据。
所以,我们需要对Person组件传递的标签属性进行类型上的限制。 在以上基础上再拓展小需求,1.当性别不传递时,默认显示男。2.姓名是必传。
稍微整理一下:
- 对props传值进行类型限制。
- 某个属性的默认值
- 必填项
如何限制?也就是对组件实例对象里的props进行限制,也就是传递的值进行限制
组件实例对象是由谁new出来?是我们定义的person组件,每写一个person组件,react都会帮我们new一个组件实例,在组件实例props中就包括了所有传递的内容。
我们先来一段伪代码,设想自己是props的设计者,该如何去限制
Person.属性规则 = {
name:'必传,字符串'
};
const p = { name: "tom", sex: "男", age: 18 };
而在react要求中,是往react实例person自身添加一个属性,属性名叫做propTypes,prop有属性的意思,type有种类的意思。当给person加上propTypes时,并添加具体规则,react就能帮你限制。
Person.propTypes = {
name:React.PropTypes
};
别写错了,两个属性非常像,PropTypes属于React内置属性。
Person.propTypes = {
name:React.PropTypes.string
};
React.PropTypes.string就是给name添加了属性限制(规则),但是我们打开控制台时,发现报错信息Uncaught TypeError: Cannot read properties of undefined (reading ‘string’),简单的理解就是不能读取sting在undefined身上,所以是.string,.的左侧出了问题。
也就是PropTypes是undefined ,这里要说明一下,在React15.xxx版本的时候,React一直在维护这个属性,之后就弃用了这个属性(由于是绑定在React上的,且不是必用属性,导致React冗余)。
需要一个库支持
Person.propTypes = {
name: PropTypes.string,
};
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(
<Person name="tom" sex="女" age={18} />,
document.getElementById("test2")
);
页面正常显示
现在我们将tom的名字改为{10}实验一下
ReactDOM.render(<Person name={10} sex="女" age={18} />,document.getElementById("test2"));
打开控制台
报错信息如下:
react.development.js:2726 Warning: Failed prop type: Invalid prop name
of type number
supplied to Person
, expected string
.
意思是,我希望是name一个string,但是得到一个number,这种控制台的明显报错,并可提示开发者正确传递属性,也就完成第一个小需求:对props传值进行类型限制。
接下来看第三个,必填项,PropTypes提供一个 isRequired
属性,来限制props的默认值,示例如下
Person.propTypes = {
name: PropTypes.string.isRequired,
};
控制台打印如下
Warning: Failed prop type: The prop name
is marked as required in Person
, but its value is undefined
.
意思是:名字被标记为必填项,但是传递了一个undefined。
这解决了第三个小需求,必填项,接下来看剩下的小需求,某个属性的默认值,这涉及到另一个属性,defaultProps
,挂载在Person实例身上。
Person.propTypes = {
name: PropTypes.string.isRequired,
};
Person.defaultProps = {
sex:'女'
}
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name='tom' age={18} />,document.getElementById("test2"));
再来看一个问题,年龄是Number类型,且不是必填的,这时我去掉age={18}
Person.propTypes = {
name: PropTypes.string.isRequired,
sex:PropTypes.string,
age:PropTypes.number
};
Person.defaultProps = {
sex:'女'
}
const p = { name: "jeery", sex: "男", age: 17 };
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name='tom' age={18} />,document.getElementById("test2"));
你会发现控制台报
这是因为
所以给一个默认值就好了,加点注释
// 指定属性类型及设置必填项
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
};
// 设置默认属性
Person.defaultProps = {
sex: "女",
age: 18,
};
另外有一个注意事项,我们可以加一点内容,比如说加一个说话的方法,并且做一个限制,想到的是function
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.function
};
// 设置默认属性
Person.defaultProps = {
sex: "女",
age: 18,
};
const p = { name: "jeery", sex: "男", age: 17 };
function speak() {
console.log("我说话了");
}
ReactDOM.render(<Person {...p} />, document.getElementById("test1"));
ReactDOM.render(<Person name="tom" speak={speak} />, document.getElementById("test2"));
打开控制台
Failed prop type: Person: prop type speak
is invalid; it must be a function, usually from the prop-types
package, but received undefined
.
这里的意思是,speak必须是个函数,但是是个undefined,这是因为funciton写的不对,如下
Person.propTypes = {
name: PropTypes.string.isRequired,
sex: PropTypes.string,
age: PropTypes.number,
speak: PropTypes.function
};
string,number没有首字母大写,是因为避免与内置String冲突,而function是定义函数的关键字,正确的写法是func