一、概念
我的理解是,是否有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.valueconst 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。