React中创建组件的方式
学习React也有一段时间了,虽然天天都在围绕着组件打转转,但在React中怎么构建组件呢并没有去深入的了解。事实上呢?在React中的组件还是有些复杂的,从概念上来说就不简单。比如说, 类组件
, 函数组件
, 无状态组件
和 高阶组件
等。另外创建组件的方式也有所不同,比如最早使用 React.createClass
来创建组件,有了ES6之后使用 extends React.Component
(借助ES6的 class
特性)创建组件,而今天又流行使用函数(Hooks)方式来创建组件。那么他们之间如何创建组件,又有何区别呢?在这篇文章中我们就先来学习和探讨在React中如何创建组件。
先来看 React.createClass
如何创建组件?
React.createClass
如果你一直以来都在使用React的话,那么对 React.createClass
这个API并不陌生。在React中,最初就是用这个API来创建React组件。将描述组件的所有信息都将作为对象传递给 createClass
。
createClass
方法为开发人员提供了一个工厂方法(Factory Method),可以在不使用JavaScript 类的情况下创建React类组件。这是在ES之前创建React组件方法之一,因为在ES5中没有可用的类语法:
const App = React.createClass({ getInitialState: function() { return { value: '大漠' } } onChange: function(e) { this.setState({ value: e.target.value }) } render: function() { return () } }) const rootElement = document.getElementById("app"); ReactDOM.render(, rootElement);使用 React.createClass 创建组件
Hello, {this.state.value} (^_^)!
上面的Demo在React V15.5版本上运行。
createClass()
方法接受一个对象,该对象为React组件定义方法。 getInitialState()
函数用于为React组件设置 初始状态
,强制使用 render()
方法在JSX中用于输出;额外的方法(比如 onChange
)是通过向对象传递更多的函数而添加的。
React中的生命周期也是可用的。例如,为了每次将值从 input
中输入存到浏览器的本地存储中( localStorage
),我们可以使用 componentDidUpdate()
生命周期,该方法是将一个函数传递给对象,对象键以React的生命周期方法命名。此外,当组件接收到初始状态时,可以从本地存储中读取该值:
const App = React.createClass({ getInitialState: function() { return { value: localStorage.getItem('userName') || '@大漠' } }, componentDidUpdate: function(){ localStorage.setItem('userName', this.state.value) }, onChange: function(e) { this.setState({ value: e.target.value }) }, render: function() { return () } }) const rootElement = document.getElementById("app"); ReactDOM.render(, rootElement);使用React.createClass创建组件
Hello, {this.state.value} (^_^)!
这个示例具有本地存储的功能,每当重新加载或刷新浏览器时,当组件第一次挂载时,应该会显示之前在 input
中输入的本地存储的初始状态。
注意:React核心包中不再提供 React.createClass()
方法。如果你想尝试它,必须安装一个额外的包: npm i create-react-class
。时至今日,应该尽可能地避免使用它。
在这里可以获取到 React.createClass()
创建组件更多的信息
。
React Mixins
React中引入了React Mixins,作为React的第一个可重用组件逻辑,这是一种高级模式。使用Mixin,可以将React组件的逻辑提取出来成为一个 独立对象
。当在组件中使用Mixin时,所有来自Mixin的特性都被引入组件:
var localStorageMixin = { getInitialState: function(){ return { value: localStorage.getItem('userName') || '@大漠' } }, setLocalStorage: function(val) { localStorage.setItem('userName', val) } } var App = React.createClass({ mixins: [localStorageMixin], componentDidUpdate: function(){ this.setLocalStorage(this.state.value) }, onChange: function(e) { this.setState({ value: e.target.value }) }, render() { return () } }) const rootElement = document.getElementById("app"); ReactDOM.render(, rootElement);使用React Mixin和createClass创建组件
Hello, {this.state.value} (^_^)!!!
本例中,Mixin提供从本地存储中读取组件的初始状态,并使用 setLocalStorage()
方法扩展组件,该方法稍后将在实际组件中使用。为了使用Mixin更加灵活,我们可以使用一个函数来返回一个对象:
function getLocalStorageMixin(localStorageKey) { return { getInitialState: function(){ return { value: localStoragee.getItem(localStorageKey) || '' } }, setLocalStorage: function(value) { localStorage.setItem(localStorageKey, value) } } } var App = React.createClass({ mixins: [getLocalStorageMixin('userName')], // ... })
注意:现在在React中不再使用Mixins了,因为它们有几个缺点。 有关于React Mixins更多的信息,可以点击这里进行了解
。
createClass()
是创建React组件的一种简单而有效的方法。React最初使用 createClass
API的原因是,当时JavaScript没有内置的 class
。当然,这种情况最终改变了。ES6开始引入了 class
这个关键字,也可以使用类来创建组件。这让React进入了一个两难的境地,
要么继续使用 createClass
,要么跟进ES6,使用 class
来创建组件
。事实证明,React选择了后者。
React.Component
React v3.13.0
版本引入了 React.Component
API,允许你使用JavaScript的类( class
)来创建React组件。在React中使用 class
创建的组件常常被称为 React 类组件
。
我们可以使用 React.Component
来重构上面使用 React.createClass()
方法创建的组件。
class App extends React.Component { constructor(props) { super(props) this.state = { value: localStorage.getItem('userName') || '@大漠' } this.onChange = this.onChange.bind(this) } componentDidUpdate() { localStorage.setItem('userName', this.state.value) } onChange(e) { this.setState({ value: e.target.value }) } render() { return () } } const rootElement = document.getElementById("app"); ReactDOM.render(, rootElement);使用ES6 Class创建组件(React.Component)
Hello, {this.state.value} (^_^)!!!
使用JavaScript类编写React组件带有类构造函数 constructor()
(主要用于React中设置初始状态或绑定方法)和 render()
方法。React组件内部所有逻辑都来自于 React.Component
。通过类组件中使用面向对象继承的组件。但是,不建议在更多的地方使用继承这个概念。相反,建议 使用组合而不是继承
。
在React中使用 React.Component
创建组件,有几个重要的概念需要掌握。
构造函数 constructor()
使用类组件,可以在构造函数 constructor()
内部将组件的状态初始化为实例( this
)上的状态属性。但是,根据ECMAScript规范,如果要扩展子类(即 React.Component
),必须要先调用 super()
,然后才能使用 this
。具体来说,在使用React时,还必须记住将 props
传递给 super()
:
class App extends React.Component { constructor(props) { super(props) // ... } // ... }
自动绑定
当使用 React.createClass
创建组件时,
React会自动将所有方法绑定到组件的实例( this
)
。而 React.Component
并非如此,很多开发人员都意识到他们不知道 this
关键字是如何工作的。因为必须记住
类构造函数中的 .bind()
方法(即 .bind(this)
)
。如果不这样做的话,浏览器会报“
无法读取未定义的 setState
属性
”错误。
class App extends React.Component { constructor(props) { super(props) //... this.onChange = this.onChange.bind(this) } // ... }
调用 super(props)
并要记住 .bind(this)
方法是比较烦人,但这里并没有什么根本的错误。但当你一天要像这样处理很多次的时候,也会令人感到烦感。庆幸的是,在从 createClass
切换到 React.Component
之后不久,
TC39就提出 Class Fields
相关的建议
。
类字段(Class Fields)
类字段允许我们直接将实例属性作为属性添加到类上,而无需使用构造函数。这样一来,我们就不再需要使用构造函数来设置组件的初始状态,也不再需要在构造函数中使用 .bind(this)
,因为我们可以使用箭头函数。
class App extends React.Component { state = { value: localStorage.getItem('userName') || '@w3cplus' } componentDidUpdate() { localStorage.setItem('userName', this.state.value) } onChange = (e) => { this.setState({ value: e.target.value }) } render () { const {value} = this.state return () } } const rootElement = document.getElementById("app"); ReactDOM.render(, rootElement);使用React.Component创建组件(Class Fields)
Hello, {value} (^_^)!!!