一、组件component(续)
1.1、组件的state
1.1.1、componentWillUnmount
componentWillUnmount()
会在组件卸载及销毁之前直接调用。在此方法中执行必要的清理操作,例如,清除 timer,取消网络请求或清除在 componentDidMount()
中创建的订阅等。
componentWillUnmount()
中不应调用 setState()
,因为该组件将永远不会重新渲染。组件实例卸载后,将永远不会再挂载它。
没搞懂!
1.2、有状态组件和无状态组件
是不是每个组件内部都需要定义state呢?当然不是。state用来反映组件内部状态变化,如果一个组件的内部状态是不变的,当然就用不到state,这样的组件称之为无状态组件,例如PostList。
反之,一个组件的内部状态会发生变化,就需要使用state 来保存变化,这种组件称为有状态组件,例如PostItem。
定义无状态组件除了使用 ES 6 class的方式外,还可以使用函数定义,一个函数组件接收props作为参数,返回代表这个组件的UI React 元素结构。
推荐使用无状态组件;
1、给帖子增加一个编号
2、
例如,下面是一个简单的函数组件:
1.3、属性校验和默认值
1.3.1、组件特殊属性——propTypes
Hi.js
function Hi (props){ return ( <div style={{color:"purple"}}> <h2>Hi,你的年龄是 {props.age}</h2> <hr></hr> </div> ) } export default Hi;
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; // import Hello from './Hello'; import PostList from './PostList'; import Hi from './Hi' const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> //<Hi name="tom"/>
<Hi age="10"/>
</React.StrictMode> );
这时不管<Hi />组件的写name也没报错,哪怕没有这个属性,但是如果写了也不会,就是结果不会显示出来,但是把年龄用string型也会显示出来,这时就需要约束,
所以正确的写法是
// 类组件 // 要分开定义。先定义组件,在定义属性 import PropTypes from 'prop-types' import React, { Component } from 'react' class Hi extends Component { render() { return ( <div> <h2>Hi,年龄is:{this.props.age}</h2> </div> ) } } // 设置组件Hi的属性 Hi.propTypes={ //约束age属性为number类型 age:PropTypes.number, } export default Hi;
index.js
let age= 19 <Hi age={age}/>
结果:
1.3.2、指定默认属性
你可以给组件分配一个特殊的defaultProps属性。
PropTypes的更多验证器
import React from 'react'; import PropTypes from 'prop-types'; class MyComponent extends React.Component { render() { // 利用属性做更多得事 } } MyComponent.propTypes = { //你可以定义一个属性是特定的JS类型(Array,Boolean,Function,Number,Object,String,Symbol)。默认情况下,这些都是可选的。 optionalArray: PropTypes.array, optionalBool: PropTypes.bool, optionalFunc: PropTypes.func, optionalNumber: PropTypes.number, optionalObject: PropTypes.object, optionalString: PropTypes.string, optionalSymbol: PropTypes.symbol, //指定类型为:任何可以被渲染的元素,包括数字,字符串,react 元素,数组,fragment。 optionalNode: PropTypes.node, // 指定类型为:一个react 元素 optionalElement: PropTypes.element, //你可以类型为某个类的实例,这里使用JS的instanceOf操作符实现 optionalMessage: PropTypes.instanceOf(Message), //指定枚举类型:你可以把属性限制在某些特定值之内 optionalEnum: PropTypes.oneOf(['News', 'Photos']), // 指定多个类型:你也可以把属性类型限制在某些指定的类型范围内 optionalUnion: PropTypes.oneOfType([ PropTypes.string, PropTypes.number, PropTypes.instanceOf(Message) ]), // 指定某个类型的数组 optionalArrayOf: PropTypes.arrayOf(PropTypes.number), // 指定类型为对象,且对象属性值是特定的类型 optionalObjectOf: PropTypes.objectOf(PropTypes.number), //指定类型为对象,且可以规定哪些属性必须有,哪些属性可以没有 optionalObjectWithShape: PropTypes.shape({ optionalProperty: PropTypes.string, requiredProperty: PropTypes.number.isRequired }), // 指定类型为对象,且可以指定对象的哪些属性必须有,哪些属性可以没有。如果出现没有定义的属性,会出现警告。 //下面的代码optionalObjectWithStrictShape的属性值为对象,但是对象的属性最多有两个,optionalProperty 和 requiredProperty。 //出现第三个属性,控制台出现警告。 optionalObjectWithStrictShape: PropTypes.exact({ optionalProperty: PropTypes.string, requiredProperty: PropTypes.number.isRequired }), //加上isReqired限制,可以指定某个属性必须提供,如果没有出现警告。 requiredFunc: PropTypes.func.isRequired, requiredAny: PropTypes.any.isRequired, // 你也可以指定一个自定义的验证器。如果验证不通过,它应该返回Error对象,而不是`console.warn `或抛出错误。`oneOfType`中不起作用。 customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error( 'Invalid prop `' + propName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } }, //你也可以提供一个自定义的验证器 arrayOf和objectOf。如果验证失败,它应该返回一个Error对象。 //验证器用来验证数组或对象的每个值。验证器的前两个参数是数组或对象本身,还有对应的key。 customArrayProp: PropTypes.arrayOf(function(propValue, key, componentName, location, propFullName) { if (!/matchme/.test(propValue[key])) { return new Error( 'Invalid prop `' + propFullName + '` supplied to' + ' `' + componentName + '`. Validation failed.' ); } })
1、基本数组类型
第一个是要给一个数组类型,但是第一步发现数据类型什么都能写,string跟number,所以在改善约束,约束hobby为数组且必须为数字
代码:
import PropTypes from 'prop-types' import React, { Component } from 'react' class Hi extends Component { render() { return ( <div> <h2>Hi,年龄is:{this.props.age},{this.props.hobby.join(",")}</h2> </div> ) } } // 设置组件Hi的属性 Hi.propTypes={ //约束age属性为number类型 age:PropTypes.number, // 约束hobby必须为数组类型 ,写之后又发现这个数组太弱了,在后面加上123也能行 // hobby:PropTypes.array, // 约束hobby必须为数字 hobby:PropTypes.arrayOf(PropTypes.number), }; export default Hi;
index.js
let age= 19 const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> {/* <Hello /> <PostList></PostList> <Tabs /> */} {/* "阅读","运动","写作" */} <Hi age={age} hobby={[1,2,3,4]} /> </React.StrictMode> );
2、弹框约束为函数
//不完整代码,只需要改两行 Hi.js render() { return ( <div> <h2 onClick={this.props.onVote}>Hi,年龄is:{this.props.age},{this.props.hobby.join(",")}</h2> </div> ) } // 约束是一个onVote属性是一个函数 onVote:PropTypes.func index.js //如果写成onVote={“hello”},这样就不满足约束,报错,没有使用函数 <Hi age={age} hobby={[1,2,3,4]} onVote={() => alert("Hello 弹框约束是需要一个函数,不写函数直接写弹框内容就报错!")}/>
基本类型,数组,函数
3、指定一个数组中选一项
代码:
<h2>性别:{this.props.sex}</h2> // 限制性别必须为男或女,数组中的一项 sex:PropTypes.oneOf(["男","女"]), <Hi age={age} hobby={[1,2,3,4]} sex="12" onVote={() => alert("Hello 弹框约束是需要一个函数,不写函数直接写弹框内容就报错!")}/>
4、info属性的值必须是message类型
Hi.js// 定义类型Massage export function Message(){ this.show=()=>{ alert("hello!") } }
// info属性的值必须是message类型 info:PropTypes.instanceOf(Message)import Hi ,{Message} from './Hi' info={new Message()}
index.js文件
5、 info可以是number,string或者Message类型中的其中一个
info:PropTypes.oneOfType([ PropTypes.number, PropTypes.string, PropTypes.instanceOf(Message), ])info={new Message()} info={12} info={“这是哪个类型都可以,但是写了true布尔类型会报错”}
6、自定义约束: 约束身高
<h2>身高:{this.props.height}</h2> // 约束身高必须在170到220之间 height:function (props,propName,componentName){ //取出属性值 let value =props[propName]; if(value<170 || value>220){ throw new Error("身高必须在170到220之间"); } }, height={200} //输入不是170到220之间报错
7、自定义约束:正则表达式电话号码
<h2>电话:{this.props.mobile}</h2> mobile:function (props,propName,componentName){ let value =props[propName]; // 两条/^ $/表示为开始结束,^1开头为1的,\d代表数字{10}且有十位 if(!/^1\d{10}$/.test(value)){ throw new Error("手机号码必须是以1开头的13位数字") } } mobile={18824553111}//要1开头且有13位
8、是否必填
// name必须为string类型且必填,基本类型必填在后面加.isRequired name:PropTypes.string.isRequired,
9、完整代码
// 定义一个函数式组件 // function Hi (props){ // return ( // <div style={{color:"purple"}}> // <h2>Hi,你的年龄是 {props.age}</h2> // <hr></hr> // </div> // ) // } // export default Hi; // 类组件 // 要分开定义。先定义组件,在定义属性 import PropTypes from 'prop-types' import React, { Component } from 'react' class Hi extends Component { render() { return ( <div> <h2 onClick={this.props.onVote}>Hi,你的姓名is:{this.props.name},年龄is:{this.props.age},{this.props.hobby.join(",")}</h2> <h2>性别:{this.props.sex}</h2> <h2>身高:{this.props.height}</h2> <h2>电话:{this.props.mobile}</h2> </div> ) } } // 定义类型Massage export function Message(){ this.show=()=>{ alert("hello!") } } // 设置组件Hi的属性 Hi.propTypes={ //约束age属性为number类型 age:PropTypes.number, // 约束hobby必须为数组类型 ,写之后又发现这个数组太弱了,在后面加上123也能行 // hobby:PropTypes.array, // 约束hobby必须为数字 hobby:PropTypes.arrayOf(PropTypes.number), // 约束是一个onVote属性是一个函数 onVote:PropTypes.func, // 限制性别必须为男或女,数组中的一项 sex:PropTypes.oneOf(["男","女"]), // info属性的值必须是message类型 // info:PropTypes.instanceOf(Message) // info可以是number,string或者Message类型中的其中一个 info:PropTypes.oneOfType([ PropTypes.number, PropTypes.string, PropTypes.instanceOf(Message), ]), // 约束身高必须在170到220之间 height:function (props,propName,componentName){ //取出属性值 let value =props[propName]; if(value<170 || value>220){ throw new Error("身高必须在170到220之间"); } }, mobile:function (props,propName,componentName){ let value =props[propName]; // 两条/^ $/表示为开始结束,^1开头为1的,\d代表数字{10}且有十位 if(value){ //先判断为不为空吧 if(!/^1\d{10}$/.test(value)){ throw new Error("手机号码必须是以1开头的13位数字") //一但不正确抛出错误 } } }, // name必须为string类型且必填,基本类型必填在后面加.isRequired name:PropTypes.string.isRequired, }; export default Hi;
import React from 'react'; import ReactDOM from 'react-dom/client'; import Hi ,{Message} from './Hi' import Timer from './Timer'; let age= 19 const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> {/* <Hello /> <PostList></PostList> <Tabs /> */} {/* "阅读","运动","写作" */} <Hi age={age} hobby={[1,2,3,4]} sex="女" info={new Message()} height={200} name="Tom" mobile={18824553111} onVote={() => alert("Hello 弹框约束是需要一个函数,不写函数直接写弹框内容就报错!")}/> </React.StrictMode> );
1.4、子元素
限制单个子元素
使用 PropTypes.element 你可以指定只有一个子元素可以被传递给组件。
Person.js
import React, { Component } from 'react' import PropTypes from 'prop-types' export default class Person extends Component { render() { return ( <div>Person</div> ) } } Person.propTypes ={ // 限制子元素必须为number类型 加上.isRequired 就是必填,不加就是空值也不会报错 children:PropTypes.number };
index.js
<Person>{19}</Person> <Person>19</Person> //错误 要number类型单写19不是number