react系列(二)高阶组件-HOC
高阶组件
简单来说,高阶组件可以看做一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。
我在之前的博客中提到一个观点,面向对象的好处就在于,易于理解,方便维护和复用。
其实高阶组件,也是为了更好地复用之前的组件。它可以理解为,基础组件通过包裹处理,生成一个适应某些场景的组件。
它可能存在于以下几种场景:
定制props
一个简单例子:
function withmorethings(wrappedcomponent) { return class extends react.component { render() { const morethings = { more: 'things', }; return <wrappedcomponent {...this.props} ...morethings/> } } }
这是hoc(high order component)最常用的一种方式,用来传递一些定制化的参数给内部组件。
提取公共方法、属性
在to b的项目中,表单是一个大头,所有流程都绕不开表单。也就会说到受控组件和非受控组件。
受控组件
由于html表单元素会保留一些内部状态,比如input框,它会有自己内部的状态来保存用户的输入值。
<input type="text" name="name" />
此时,为了能够处理将react的state和表单元素的内部状态统一起来,react提供了一种称为“受控组件”的技术。
class nameinput extends react.component { constructor(props) { super(props); this.state = {value: ''}; this.handlechange = this.handlechange.bind(this); } handlechange(event) { console.log(this); this.setstate({value: event.target.value}); } render() { return ( <input type="text" value={this.state.value} onchange={this.handlechange} /> ); } }
通过内部的state和绑定change事件,就可以将input内部的处理机制转移到react的默认处理机制上,收到react的控制。
但是,还是有一些元素,不能使用这种方法,比如
<input type="file">
这个元素是只读的,用户选择完毕后,可以获取到对应的文件。不能通过react内部的state来模拟。
这就引出了——
非受控组件
非受控组件从dom中获取表单值,而不是通过react的state来处理。由于它不经过react的一些逻辑,所以不能对它的状态做监控。这里有一篇文章controlled and uncontrolled form inputs in react don't have to be complicated介绍了何时可以使用非受控组件。
下面是一个非受控组件的例子:
import react, { component } from "react"; export default class nameinput extends component { constructor(props) { super(props); } handlechange(event) { console.log(this); this.setstate({ value: event.target.value }); } render() { return ( <input type="text" defaultvalue="test" ref={input => (this.input = input)} /> ); } }
<input type="checkbox"> 和 <input type="radio"> 支持 defaultchecked,<input type="text"><select> 和 <textarea> 支持 defaultvalue,可以帮助设置表单默认值。
非受控组件通过ref来获取dom元素,然后根据当前dom去更新ui。
有关ref的使用,参考这个文档refs & dom。
我个人建议,如果对于一些数据交互较少,展示和处理基本在组件内部完成,不会涉及到很多组件间数据交换的情景,可以使用非受控组件,更快,更直观。其他情况仍然建议使用受控组件,方便数据流的传导。
=================================
接着说回高阶组件。在使用表单时,很多情境下的输入,我们都希望统一由state,或者redux来保存,而不是被dom节点存储。
上面讲到了受控组件的使用,关键点有三:
1.对应的onchange方法
2.对应的存储点,state或者redux
3.绑定到对应组件
参考上面的描述,来实现一个高阶组件的生成函数。
这里是一个例子:
这样就可以很方便的生成受控组件。
在一些场景下,我们也可以用其他组件包装wrappedcomponent。比如,添加一些小图标,用父组件可能不够灵活,用hoc则可以很轻松地生成一个可配置的组件,灵活许多。
在react higher order components in depth还提到一种生成hoc的方法,类继承,改写更彻底。详细内容可以参考这篇文章。也可以查看知乎的这篇翻译深入理解 react 高阶组件。
以上,感谢阅读。