博客
zyzcos.gitee.io
Render Props
什么是Render Props
个人初步理解:就是通过
this.props.render()
这个函数,将state
作为接口并对外开放,外部组件通过改变state
,引起内部state
变化,从而发生重渲染。
如何理解Render Props的作用
假如有一个监测鼠标坐标的组件
class Mouse extends React.Component {
constructor(props){
super(props);
this.state = {
x:0,
y:0
}
this.handleMouseMove = this.handleMouseMove.bind(this);
}
handleMouseMove(event){
this.setState({
x:event.clientX,
y:event.clientY
})
}
render(){
return (
<Fragment>
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}></div>
<div>当前鼠标的坐标为:({ this.state.x },{this.state.y})</div>
</Fragment>
)
}
}
现在需要在另外一个组件中,调用这个功能。有两种实现方法
- 方法1:通过
Props
传参的方法,将数据传给Cat
组件使用:
class Cat extends React.Component {
constructor(props){
super(props);
}
render(){
const mouse = this.props.mouse;
return (
<img src='./cat.jpg' style={{ position: 'absolute', left: mouse.x, top: mouse.y }}>
)
}
}
// 下面是Mouse组件内,render函数内容
render(){
return (
<Fragment>
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}></div>
<Cat mouse={this.state}>
</Fragment>
)
}
但是,如果其他组件也要使用的话,需要修改
Mouse
中的render方法
,不能体现出复用
的感觉
- 方法2:使用
this.props.render()
抛出数据
class Mouse extends React.Component {
constructor(props){
super(props);
this.state = {
x:0,
y:0
}
this.handleMouseMove = this.handleMouseMove.bind(this);
}
handleMouseMove(event){
this.setState({
x:event.clientX,
y:event.clientY
})
}
render(){
return (
<Fragment>
<div style={{ height: '100vh' }} onMouseMove={this.handleMouseMove}></div>
{ this.props.render(this.state) } // 对外抛出关键数据
</Fragment>
)
}
}
class App extends React.Component {
constructor(props){
super(props);
}
render(){
return(
<Mouse
render={ mouse => { // 这里的mouse参数,就是this.props.render抛出的this.state
<Cat mouse={mouse}> // 这个函数的返回值,最终会渲染在 { this.props.render(this.state) } 这个位置
}}
>
)
}
}
其实两个方法本质不变,也就是
Mouse
里面嵌套了Cat
,但是方法2中,不需要每次使用都修改里面的代码,只需要完成一次调用就可以。
静态类型检查
静态类型检查器是什么?
是:可以在运行前识别某些类型的问题。其实可以理解为DEBUG的工具吧
静态类型检查器有哪些?
- Flow,Facebook开发的
- TypeScript,可以在构建的时候发现错误
严格模式
什么是严格模式
在
JavaScript
和Vue.js
的学习中,都接触到了严格模式
,其实就是感觉就是将弱类型语言
变为强类型语言
如何使用严格模式
将其包裹在
<React.StrictMode>
中就可以了
render(){
return (
<React.StrictMode>
<div>
<ComponentOne />
<ComponentTwo />
</div>
</React.StrictMode>
)
}
使用严格模式有什么作用?
1. 识别不安全的生命周期
某些过时的
生命周期方法
在异步React中使用是不安全的,平时写可以注意到。但是你调用第三方库,又不知道里面使用了过时的生命周期方法
,你却把他放到了异步React中,这样就不安全了。如果使用严格模式,就可以避免这个问题
2. 关于使用过时字符串ref API的警告
React 提供了两种方法管理 refs 的方式:已过时的字符串 ref API 的形式及回调函数 API 的形式。前者由于有缺陷,所以官方推荐使用后者。进而严格模式下,使用前者会抛出警告。
3. 关于使用废弃findDOMNode
方法的警告
现在由于可以使用
refs
来获取节点,所以就废弃了findDOMNode
4. 检测意外的副作用
5. 检测过时的context API
PropType
什么是PropType
React内置的类型检查功能。
个人理解,类似于
Vue.js2.x
接收props
时候的验证器
// VUE中
const app = new Vue({
el:'#app',
props:{
name:{
type:String
},
phone:{
type:String
}
}
})
如何使用PropType
import PropTypes from 'prop-types';
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
Greeting.propTypes = {
name: PropTypes.string
};
验证器分类
import PropTypes from 'prop-types';
MyComponent.propTypes = {
// 你可以将属性声明为 JS 原生类型,默认情况下
// 这些属性都是可选的。
optionalArray: PropTypes.array,
optionalBool: PropTypes.bool,
optionalFunc: PropTypes.func,
optionalNumber: PropTypes.number,
optionalObject: PropTypes.object,
optionalString: PropTypes.string,
optionalSymbol: PropTypes.symbol,
// 任何可被渲染的元素(包括数字、字符串、元素或数组)
// (或 Fragment) 也包含这些类型。
optionalNode: PropTypes.node,
// 一个 React 元素。
optionalElement: PropTypes.element,
// 一个 React 元素类型(即,MyComponent)。
optionalElementType: PropTypes.elementType,
// 你也可以声明 prop 为类的实例,这里使用
// JS 的 instanceof 操作符。
optionalMessage: PropTypes.instanceOf(Message),
// 你可以让你的 prop 只能是特定的值,指定它为
// 枚举类型。
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({
color: PropTypes.string,
fontSize: PropTypes.number
}),
// An object with warnings on extra properties
optionalObjectWithStrictShape: PropTypes.exact({
name: PropTypes.string,
quantity: PropTypes.number
}),
// 你可以在任何 PropTypes 属性后面加上 `isRequired` ,确保
// 这个 prop 没有被提供时,会打印警告信息。
requiredFunc: PropTypes.func.isRequired,
// 任意类型的数据
requiredAny: PropTypes.any.isRequired,
// 你可以指定一个自定义验证器。它在验证失败时应返回一个 Error 对象。
// 请不要使用 `console.warn` 或抛出异常,因为这在 `onOfType` 中不会起作用。
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error(
'Invalid prop `' + propName + '` supplied to' +
' `' + componentName + '`. Validation failed.'
);
}
},
// 你也可以提供一个自定义的 `arrayOf` 或 `objectOf` 验证器。
// 它应该在验证失败时返回一个 Error 对象。
// 验证器将验证数组或对象中的每个值。验证器的前两个参数
// 第一个是数组或对象本身
// 第二个是他们当前的键。
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.'
);
}
})
};
props限制单个元素
import PropTypes from 'prop-types';
class MyComponent extends React.Component {
render() {
// 这必须只有一个元素,否则控制台会打印警告。
const children = this.props.children;
return (
<div>
{children}
</div>
);
}
}
MyComponent.propTypes = {
children: PropTypes.element.isRequired
};
props默认值
在class之外
class Greeting extends React.Component {
render() {
return (
<h1>Hello, {this.props.name}</h1>
);
}
}
// 指定 props 的默认值:
Greeting.defaultProps = {
name: 'Stranger'
};
// 渲染出 "Hello, Stranger":
ReactDOM.render(
<Greeting />,
document.getElementById('example')
);
在class内
class Greeting extends React.Component {
static defaultProps = {
name: 'stranger'
}
render() {
return (
<div>Hello, {this.props.name}</div>
)
}
}
非受控组件
什么是受控组件
将
HTML内置的控制组件
的提交操作、数据操作全部由React的函数、状态替换
什么是非受控组件
HTML内置的控制组件
提交操作本身执行,数据操作由React组件
利用refs
进行获取.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
this.state = {
input:"",
}
}
// 在受控组件中,还需要对数据进行获取
/*
onChange(event){
this.setState({
input:event.target.value
})
}
*/
handleSubmit(event) {
// 在非受控组件中,通过refs就可以直接获取dom元素
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
默认值
- defaultValue
<input type='text' defaultValue='Tom'>
- defaultChecked
<input type='radio' defaultChecked >
文件输入
<input type="file" />
一直是由用户设置的,所以是一个受控组件。
WebComponent
另一种
组件开发方式