React—8—受控组件和非受控组件;高阶组件
一、概念
我的理解是,是否有react提供数据,分为受控组件和非受控组件。
比如input元素,只要绑定了value属性,那么在react中,用户在输入框输入的值不会显示在输入框(react应该做了限制,原生html的input框即使value绑定了值依然可以输入),
这就导致,想改变value的值,必须监听onChange事件,然后再onChange事件里拿到用户输入的值然后再去改变message,然后value才改变。

二、使用受控组件来使用表单
import React, { PureComponent, createRef, forwardRef } from 'react';
// 编写一个组件
class App extends PureComponent {
constructor() {
super();
this.state = {
username: '',
password: '',
isAgeree: false,
hobbies: [
{ value: 'sing', text: '唱', isChecked: false },
{ value: 'dance', text: '跳', isChecked: false },
{ value: 'rap', text: 'rap', isChecked: false }
],
fruit: '',
fruits: []
};
}
handleSumbit = event => {
// 先阻止默认的事件提交。
event.preventDefault();
console.log(this.state)
};
handleChange = e => {
// 对于类型为text或者password的输入框, 可以给input框绑定一个name属性值,然后可以通过可以e.target.name获取绑定的name属性值。
// 通过e.target.value获取到输入框的值
console.log('[ ] >', e.target, e.target.name);
const { name, value } = e.target;
this.setState({ [name]: value });
};
handleCheckBox = e => {
// 对于checkbox类型的输入框, 可以通过e.target.checked获取到是否选中的ture或false; e.target.value没有值。
const { checked } = e.target;
this.setState({ isAgeree: checked });
};
handleHobbies = (e, index) => {
console.log(e);
const hobbies = [...this.state.hobbies];
hobbies[index]['isChecked'] = e.target.checked;
this.setState({ hobbies });
};
handleSelect(event) {
// seleced选中的值在event.target.selectedOptions.value
const fruit = event.target.selectedOptions.value;
this.setState({ fruit });
}
handleSelectMultiple(event) {
//多选情况下,seleced选中的值在event.target.selectedOptions是一个集合,需要先用array.from转化为一个数组,这样就可以用数组的方法了。
const selectedArr = Array.from(event.target.selectedOptions);
const fruits = selectedArr.map(e => e.value);
this.setState({ fruits });
}
render() {
const { username, password, isAgeree, hobbies, fruit, fruits } = this.state;
return (
<div>
<form onSubmit={e => this.handleSumbit(e)}>
{/* 受控组件---输入框 */}
<div>
<label htmlFor="username">
用户名:
<input type="text" name="username" value={username} onChange={e => this.handleChange(e)} />
</label>
<label htmlFor="password">
密码:
<input type="password" name="password" value={password} onChange={e => this.handleChange(e)} />
</label>
</div>
{/* 受控组件---单选框 */}
<input type="checkbox" checked={isAgeree} onChange={e => this.handleCheckBox(e)} />
同意协议
{/* 受控组件---多选框 */}
<div>
{hobbies.map((item, index) => {
return (
<div key={item.text}>
<input type="checkbox" id={item.value} checked={item.isChecked} onChange={e => this.handleHobbies(e, index)} />
{item.text}
</div>
);
})}
</div>
{/* 受控组件---下拉框()单选 */}
<select name="" id="" value={fruit} onChange={e => this.handleSelect(e)}>
<option value="orange">橘子</option>
<option value="bnana">香蕉</option>
<option value="putao">葡萄</option>
</select>
{/* 受控组件---下拉框()多选 按住ctrl键可以实现多选 */}
<select name="" id="" value={fruits} onChange={e => this.handleSelectMultiple(e)} multiple>
<option value="orange">橘子</option>
<option value="bnana">香蕉</option>
<option value="putao">葡萄</option>
</select>
<button type="submit">登录</button>
</form>
</div>
);
}
}
export default App;
三、高阶组件hoc
3.1什么是高阶组件
什么是高阶组件呢?
相信很多同学都知道(听说过?),也用过 高阶函数, 它们非常相似,所以我们可以先来回顾一下什么是 高阶函数。
高阶函数的维基百科定义:至少满足以下条件之一:
- 接受一个或多个函数作为输入;
- 输出一个函数;
JavaScript中比较常见的filter、map、reduce都是高阶函数。
那么说明是高阶组件呢?
高阶组件的英文是 Higher-Order Components,简称为 HOC;
官方的定义:高阶组件是参数为组件,返回值为新组件的函数;
我们可以进行如下的解析:
- 首先, 高阶组件 本身不是一个组件,而是一个函数;
- 其次,这个函数的参数是一个组件,返回值也是一个组件;
我们前面用的memo()和forwardRef()都是高阶组件。
3.2高阶组件目的是
1.对组件做拦截做处理
2.处理代码是可复用的。不用对每一个要拦截的代码,都写一遍处理代码,那是在他麻烦了。
3.3举例
这里,我们可以计算每个页面的挂载时长。
得到一个组件,可以通过props给他传递一些信息,然后最终返回一个组件(类组件和函数组件都可以),
import { PureComponent } from 'react';
function logMountTime(OriginComponent) {
return class extends PureComponent {
constructor() {
super();
this.state = {
foo: '这里可以添加一些处理操作'
};
}
UNSAFE_componentWillMount() {
this.beginTime = new Date().getTime();
}
componentDidMount() {
this.endTime = new Date().getTime();
console.log(`页面${OriginComponent.name}渲染时间是${this.endTime - this.beginTime}ms`);
}
render() {
return <OriginComponent {...this.state}></OriginComponent>;
}
};
}
export default logMountTime;
Head组件用高阶组件包裹之后,再export default logMountTime(Head)返回出去。
import React, { PureComponent } from 'react'
import { } from './hoc'
import logMountTime from './hoc'
export class Head extends PureComponent {
render() {
return (
<div>
Head
{this.props.foo}
<ul>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
<li>数据列表</li>
</ul>
</div>
)
}
}
// export default Head
export default logMountTime(Head)
由于Head组件里是用的export Default导出的,所以App在引入的时候可以自己起别名,那就还叫Head,然后由于App组件正常引入即可展示。
import React, { PureComponent, } from 'react';
import Head from './Head.jsx'
// 编写一个组件
class App extends PureComponent {
constructor() {
super();
this.state = {
};
}
render() {
return (
<div>
<Head></Head>
</div>
);
}
}
export default App;
3.4发展历程
由于hoc也可以给组件复制props,如果嵌套过多,可以出现同一个叫name的props被重复赋值。

mixin没必要学了,hoc可以理解,重点掌握后面的hooks。

浙公网安备 33010602011771号