這篇文章主要介紹了react高階組件和ES6裝飾器的使用示例,具有一定借鑒價(jià)值,需要的朋友可以參考下。希望大家閱讀完這篇文章后大有收獲。下面讓小編帶著大家一起了解一下。

專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站制作服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)永和免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了近千家企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
一 裝飾者模式
優(yōu)先使用對(duì)象組合而不是類繼承。 --《設(shè)計(jì)模式》
1.什么是裝飾者模式
定義:動(dòng)態(tài)的給對(duì)象添加一些額外的屬性或行為。相比于使用繼承,裝飾者模式更加靈活。
2.裝飾者模式參與者
Component:裝飾者和被裝飾者共同的父類,是一個(gè)接口或者抽象類,用來(lái)定義基本行為
ConcreteComponent:定義具體對(duì)象,即被裝飾者
Decorator:抽象裝飾者,繼承自Component,從外類來(lái)擴(kuò)展ConcreteComponent。對(duì)于ConcreteComponent來(lái)說(shuō),不需要知道Decorator的存在,Decorator是一個(gè)接口或抽象類
ConcreteDecorator:具體裝飾者,用于擴(kuò)展ConcreteComponent
注:裝飾者和被裝飾者對(duì)象有相同的超類型,因?yàn)檠b飾者和被裝飾者必須是一樣的類型,這里利用繼承是為了達(dá)到類型匹配,而不是利用繼承獲得行為。
利用繼承設(shè)計(jì)子類,只能在編譯時(shí)靜態(tài)決定,并且所有子類都會(huì)繼承相同的行為;利用組合的做法擴(kuò)展對(duì)象,就可以在運(yùn)行時(shí)動(dòng)態(tài)的進(jìn)行擴(kuò)展。裝飾者模式遵循開(kāi)放-關(guān)閉原則:類應(yīng)該對(duì)擴(kuò)展開(kāi)放,對(duì)修改關(guān)閉。利用裝飾者,我們可以實(shí)現(xiàn)新的裝飾者增加新的行為而不用修改現(xiàn)有代碼,而如果單純依賴?yán)^承,每當(dāng)需要新行為時(shí),還得修改現(xiàn)有的代碼。
javascript 如何使用裝飾者模式
javascript 動(dòng)態(tài)語(yǔ)言的特性使得使用裝飾器模式十分的簡(jiǎn)單,文章主要內(nèi)容會(huì)介紹兩種使用裝飾者模式的實(shí)際例子。
二 react高階組件
我們都知道高階函數(shù)是什么, 高階組件其實(shí)是差不多的用法,只不過(guò)傳入的參數(shù)變成了react組件,并返回一個(gè)新的組件.
A higher-order component is a function that takes a component and returns a new component.
形如:
const EnhancedComponent = higherOrderComponent(WrappedComponent);
高階組件是react應(yīng)用中很重要的一部分,最大的特點(diǎn)就是重用組件邏輯。它并不是由React API定義出來(lái)的功能,而是由React的組合特性衍生出來(lái)的一種設(shè)計(jì)模式。
如果你用過(guò)redux,那你就一定接觸過(guò)高階組件,因?yàn)閞eact-redux中的connect就是一個(gè)高階組件。
先來(lái)一個(gè)最簡(jiǎn)單的高階組件
import React, { Component } from 'react';
import simpleHoc from './simple-hoc';
class Usual extends Component {
render() {
console.log(this.props, 'props');
return (
<div>
Usual
</div>
)
}
}
export default simpleHoc(Usual);
import React, { Component } from 'react';
const simpleHoc = WrappedComponent => {
console.log('simpleHoc');
return class extends Component {
render() {
return <WrappedComponent {...this.props}/>
}
}
}
export default simpleHoc;組件Usual通過(guò)simpleHoc的包裝,打了一個(gè)log... 那么形如simpleHoc就是一個(gè)高階組件了,通過(guò)接收一個(gè)組件class Usual,并返回一個(gè)組件class。 其實(shí)我們可以看到,在這個(gè)函數(shù)里,我們可以做很多操作。 而且return的組件同樣有自己的生命周期,function,另外,我們看到也可以把props傳給WrappedComponent(被包裝的組件)。
實(shí)現(xiàn)高階組件的方法有兩種
屬性代理(props proxy)。高階組件通過(guò)被包裹的 React 組件來(lái)操作 props。
反向繼承(inheritance inversion)。高階組件繼承于被包裹的 React 組件。
屬性代理
引入里我們寫的最簡(jiǎn)單的形式,就是屬性代理(Props Proxy)的形式。通過(guò)hoc包裝wrappedComponent,也就是例子中的Usual,本來(lái)傳給Usual的props,都在hoc中接受到了,也就是props proxy。 由此我們可以做一些操作
1.操作props
最直觀的就是接受到props,我們可以做任何讀取,編輯,刪除的很多自定義操作。包括hoc中定義的自定義事件,都可以通過(guò)props再傳下去。
import React, { Component } from 'react';
const propsProxyHoc = WrappedComponent => class extends Component {
handleClick() {
console.log('click');
}
render() {
return (<WrappedComponent
{...this.props}
handleClick={this.handleClick}
/>);
}
};
export default propsProxyHoc;然后我們的Usual組件render的時(shí)候, console.log(this.props) 會(huì)得到handleClick.
2.refs獲取組件實(shí)例
當(dāng)我們包裝Usual的時(shí)候,想獲取到它的實(shí)例怎么辦,可以通過(guò)引用(ref),在Usual組件掛載的時(shí)候,會(huì)執(zhí)行ref的回調(diào)函數(shù),在hoc中取到組件的實(shí)例。
import React, { Component } from 'react';
const refHoc = WrappedComponent => class extends Component {
componentDidMount() {
console.log(this.instanceComponent, 'instanceComponent');
}
render() {
return (<WrappedComponent
{...this.props}
ref={instanceComponent => this.instanceComponent = instanceComponent}
/>);
}
};
export default refHoc;3.抽離state
這里不是通過(guò)ref獲取state, 而是通過(guò) { props, 回調(diào)函數(shù) } 傳遞給wrappedComponent組件,通過(guò)回調(diào)函數(shù)獲取state。這里用的比較多的就是react處理表單的時(shí)候。通常react在處理表單的時(shí)候,一般使用的是受控組件(文檔),即把input都做成受控的,改變value的時(shí)候,用onChange事件同步到state中。當(dāng)然這種操作通過(guò)Container組件也可以做到,具體的區(qū)別放到后面去比較。看一下代碼就知道怎么回事了:
import React, { Component } from 'React';
const MyContainer = (WrappedComponent) => class extends Component {
constructor(props) { super(props);
this.state = {
name: '', 4
};
this.onNameChange = this.onNameChange.bind(this);
}
onNameChange(event) {
this.setState({
name: event.target.value,
})
}
render() {
const newProps = {
name: {
value: this.state.name,
onChange: this.onNameChange,
},
}
return <WrappedComponent {...this.props} {...newProps} />;
}
}在這個(gè)例子中,我們把 input 組件中對(duì) name prop 的 onChange 方法提取到高階組件中,這樣就有效地抽象了同樣的 state 操作。
反向繼承
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
return super.render();
}
}正如所見(jiàn),高階組件返回的組件繼承于 WrappedComponent。因?yàn)楸粍?dòng)地繼承了 WrappedCom- ponent,所有的調(diào)用都會(huì)反向,這也是這種方法的由來(lái)。
這種方法與屬性代理不太一樣。它通過(guò)繼承 WrappedComponent 來(lái)實(shí)現(xiàn),方法可以通過(guò) super 來(lái)順序調(diào)用。因?yàn)橐蕾囉诶^承的機(jī)制,HOC 的調(diào)用順序和隊(duì)列是一樣的:
didmount→HOC didmount→(HOCs didmount)→will unmount→HOC will unmount→(HOCs will unmount)
在反向繼承方法中,高階組件可以使用 WrappedComponent 引用,這意味著它可以使用WrappedComponent 的 state、props 、生命周期和 render 方法。但它不能保證完整的子組件樹被解析。
1.渲染劫持
渲染劫持指的就是高階組件可以控制 WrappedComponent 的渲染過(guò)程,并渲染各種各樣的結(jié) 果。我們可以在這個(gè)過(guò)程中在任何 React 元素輸出的結(jié)果中讀取、增加、修改、刪除 props,或 讀取或修改 React 元素樹,或條件顯示元素樹,又或是用樣式控制包裹元素樹。
正如之前說(shuō)到的,反向繼承不能保證完整的子組件樹被解析,這意味著將限制渲染劫持功能。 渲染劫持的經(jīng)驗(yàn)法則是我們可以操控 WrappedComponent 的元素樹,并輸出正確的結(jié)果。但如果 元素樹中包括了函數(shù)類型的 React 組件,就不能操作組件的子組件。
我們先來(lái)看條件渲染的示例:
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
if (this.props.loggedIn) {
return super.render();
} else {
return null;
}
}
}第二個(gè)示例是我們可以對(duì) render 的輸出結(jié)果進(jìn)行修改:
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
const elementsTree = super.render();
let newProps = {};
if (elementsTree && elementsTree.type === 'input') {
newProps = {value: 'may the force be with you'};
}
const props = Object.assign({}, elementsTree.props, newProps);
const newElementsTree = React.cloneElement(elementsTree, props, elementsTree.props.children);
return newElementsTree;
}
}在這個(gè)例子中,WrappedComponent 的渲染結(jié)果中,頂層的 input 組件的 value 被改寫為 may the force be with you。因此,我們可以做各種各樣的事,甚至可以反轉(zhuǎn)元素樹,或是改變?cè)?樹中的 props。這也是 Radium 庫(kù)構(gòu)造的方法。
2.控制state
高階組件可以讀取、修改或刪除 WrappedComponent 實(shí)例中的 state,如果需要的話,也可以 增加 state。但這樣做,可能會(huì)讓 WrappedComponent 組件內(nèi)部狀態(tài)變得一團(tuán)糟。大部分的高階組 件都應(yīng)該限制讀取或增加 state,尤其是后者,可以通過(guò)重新命名 state,以防止混淆。
我們來(lái)看一個(gè)例子:
const MyContainer = (WrappedComponent) => class extends WrappedComponent {
render() {
return (
<p>
<h3>HOC Debugger Component</h3>
<p>Props</p>
<pre>{JSON.stringify(this.props, null, 2)}</pre>
<p>State</p>
<pre>{JSON.stringify(this.state, null, 2)}</pre>
{super.render()}
</p> );
}
}在這個(gè)例子中,顯示了 WrappedComponent 的 props 和 state,以方便我們?cè)诔绦蛑腥フ{(diào)試它們。
高階組件可以看做是裝飾器模式(Decorator Pattern)在React的實(shí)現(xiàn)。即允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能,同時(shí)又不改變其結(jié)構(gòu),屬于包裝模式(Wrapper Pattern)的一種
ES7中添加了一個(gè)decorator的屬性,使用@符表示,可以更精簡(jiǎn)的書寫。那上面的例子就可以改成:
import React, { Component } from 'react';
import simpleHoc from './simple-hoc';
@simpleHoc
export default class Usual extends Component {
render() {
return (
<p>
Usual
</p>
)
}
}
//simple-hoc
const simpleHoc = WrappedComponent => {
console.log('simpleHoc');
return class extends Component {
render() {
return <WrappedComponent {...this.props}/>
}
}
}和高階組件是同樣的效果。
類的裝飾
@testable
class MyTestableClass {
// ...
}
function testable(target) {
target.isTestable = true;
}
MyTestableClass.isTestable // true上面代碼中,@testable 就是一個(gè)裝飾器。它修改了 MyTestableClass這 個(gè)類的行為,為它加上了靜態(tài)屬性isTestable。testable 函數(shù)的參數(shù) target 是 MyTestableClass 類本身。
如果覺(jué)得一個(gè)參數(shù)不夠用,可以在裝飾器外面再封裝一層函數(shù)。
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false上面代碼中,裝飾器 testable 可以接受參數(shù),這就等于可以修改裝飾器的行為。
方法的裝飾
裝飾器不僅可以裝飾類,還可以裝飾類的屬性。
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}上面代碼中,裝飾器 readonly 用來(lái)裝飾“類”的name方法。
裝飾器函數(shù) readonly 一共可以接受三個(gè)參數(shù)。
function readonly(target, name, descriptor){
// descriptor對(duì)象原來(lái)的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 類似于
Object.defineProperty(Person.prototype, 'name', descriptor);裝飾器第一個(gè)參數(shù)是 類的原型對(duì)象,上例是 Person.prototype,裝飾器的本意是要“裝飾”類的實(shí)例,但是這個(gè)時(shí)候?qū)嵗€沒(méi)生成,所以只能去裝飾原型(這不同于類的裝飾,那種情況時(shí)target參數(shù)指的是類本身);
第二個(gè)參數(shù)是 所要裝飾的屬性名
第三個(gè)參數(shù)是 該屬性的描述對(duì)象
另外,上面代碼說(shuō)明,裝飾器(readonly)會(huì)修改屬性的 描述對(duì)象(descriptor),然后被修改的描述對(duì)象再用來(lái)定義屬性。
ES5 中,mixin 為 object 提供功能“混合”能力,由于 JavaScript 的原型繼承機(jī)制,通過(guò) mixin 一個(gè)或多個(gè)對(duì)象到構(gòu)造器的 prototype上,能夠間接提供為“類”的實(shí)例混合功能的能力。
下面是例子:
function mixin(...objs){
return objs.reduce((dest, src) => {
for (var key in src) {
dest[key] = src[key]
}
return dest;
});
}
function createWithPrototype(Cls){
var P = function(){};
P.prototype = Cls.prototype;
return new P();
}
function Person(name, age, gender){
this.name = name;
this.age = age;
this.gender = gender;
}
function Employee(name, age, gender, level, salary){
Person.call(this, name, age, gender);
this.level = level;
this.salary = salary;
}
Employee.prototype = createWithPrototype(Person);
mixin(Employee.prototype, {
getSalary: function(){
return this.salary;
}
});
function Serializable(Cls, serializer){
mixin(Cls, serializer);
this.toString = function(){
return Cls.stringify(this);
}
}
mixin(Employee.prototype, new Serializable(Employee, {
parse: function(str){
var data = JSON.parse(str);
return new Employee(
data.name,
data.age,
data.gender,
data.level,
data.salary
);
},
stringify: function(employee){
return JSON.stringify({
name: employee.name,
age: employee.age,
gender: employee.gender,
level: employee.level,
salary: employee.salary
});
}
})
);從一定程度上,mixin 彌補(bǔ)了 JavaScript 單一原型鏈的缺陷,可以實(shí)現(xiàn)類似于多重繼承的效果。在上面的例子里,我們讓 Employee “繼承” Person,同時(shí)也“繼承” Serializable。有趣的是我們通過(guò) mixin Serializable 讓 Employee 擁有了 stringify 和 parse 兩個(gè)方法,同時(shí)我們改寫了 Employee 實(shí)例的 toString 方法。
我們可以如下使用上面定義的類:
var employee = new Employee("jane",25,"f",1,1000);
var employee2 = Employee.parse(employee+""); //通過(guò)序列化反序列化復(fù)制對(duì)象
console.log(employee2,
employee2 instanceof Employee, //true
employee2 instanceof Person, //true
employee == employee2); //falseES6 中的 mixin 式繼承
在 ES6 中,我們可以采用全新的基于類繼承的 “mixin” 模式設(shè)計(jì)更優(yōu)雅的“語(yǔ)義化”接口,這是因?yàn)?ES6 中的 extends 可以繼承動(dòng)態(tài)構(gòu)造的類,這一點(diǎn)和其他的靜態(tài)聲明類的編程語(yǔ)言不同,在說(shuō)明它的好處之前,我們先看一下 ES6 中如何更好地實(shí)現(xiàn)上面 ES5 代碼里的 Serializable:
用繼承實(shí)現(xiàn) Serializable
class Serializable{
constructor(){
if(typeof this.constructor.stringify !== "function"){
throw new ReferenceError("Please define stringify method to the Class!");
}
if(typeof this.constructor.parse !== "function"){
throw new ReferenceError("Please define parse method to the Class!");
}
}
toString(){
return this.constructor.stringify(this);
}
}
class Person extends Serializable{
constructor(name, age, gender){
super();
Object.assign(this, {name, age, gender});
}
}
class Employee extends Person{
constructor(name, age, gender, level, salary){
super(name, age, gender);
this.level = level;
this.salary = salary;
}
static stringify(employee){
let {name, age, gender, level, salary} = employee;
return JSON.stringify({name, age, gender, level, salary});
}
static parse(str){
let {name, age, gender, level, salary} = JSON.parse(str);
return new Employee(name, age, gender, level, salary);
}
}
let employee = new Employee("jane",25,"f",1,1000);
let employee2 = Employee.parse(employee+""); //通過(guò)序列化反序列化復(fù)制對(duì)象
console.log(employee2,
employee2 instanceof Employee, //true
employee2 instanceof Person, //true
employee == employee2); //false
上面的代碼,我們用 ES6 的類繼承實(shí)現(xiàn)了 Serializable,與 ES5 的實(shí)現(xiàn)相比,它非常簡(jiǎn)單,首先我們?cè)O(shè)計(jì)了一個(gè) Serializable 類:
class Serializable{
constructor(){
if(typeof this.constructor.stringify !== "function"){
throw new ReferenceError("Please define stringify method to the Class!");
}
if(typeof this.constructor.parse !== "function"){
throw new ReferenceError("Please define parse method to the Class!");
}
}
toString(){
return this.constructor.stringify(this);
}
}它檢查當(dāng)前實(shí)例的類上是否有定義 stringify 和 parse 靜態(tài)方法,如果有,使用靜態(tài)方法重寫 toString 方法,如果沒(méi)有,則在實(shí)例化對(duì)象的時(shí)候拋出一個(gè)異常。
這么設(shè)計(jì)挺好的,但它也有不足之處,首先注意到我們將 stringify 和 parse 定義到 Employee 上,這沒(méi)有什么問(wèn)題,但是如果我們實(shí)例化 Person,它將報(bào)錯(cuò):
let person = new Person("john", 22, "m");
//Uncaught ReferenceError: Please define stringify method to the Class!這是因?yàn)?strong>我們沒(méi)有在 Person 上定義 parse 和 stringify 方法。因?yàn)?Serializable 是一個(gè)基類,在只支持單繼承的 ES6 中,如果我們不需要 Person 可序列化,只需要 Person 的子類 Employee 可序列化,靠這種繼承鏈?zhǔn)亲霾坏降摹?/p>
另外,如何用 Serializable 讓 JS 原生類的子類(比如 Set、Map)可序列化?
所以,我們需要考慮改變一下我們的設(shè)計(jì)模式:
用 mixin 實(shí)現(xiàn) Serilizable
const Serializable = Sup => class extends Sup {
constructor(...args){
super(...args);
if(typeof this.constructor.stringify !== "function"){
throw new ReferenceError("Please define stringify method to the Class!");
}
if(typeof this.constructor.parse !== "function"){
throw new ReferenceError("Please define parse method to the Class!");
}
}
toString(){
return this.constructor.stringify(this);
}
}
class Person {
constructor(name, age, gender){
Object.assign(this, {name, age, gender});
}
}
class Employee extends Serializable(Person){
constructor(name, age, gender, level, salary){
super(name, age, gender);
this.level = level;
this.salary = salary;
}
static stringify(employee){
let {name, age, gender, level, salary} = employee;
return JSON.stringify({name, age, gender, level, salary});
}
static parse(str){
let {name, age, gender, level, salary} = JSON.parse(str);
return new Employee(name, age, gender, level, salary);
}
}
let employee = new Employee("jane",25,"f",1,1000);
let employee2 = Employee.parse(employee+""); //通過(guò)序列化反序列化復(fù)制對(duì)象
console.log(employee2,
employee2 instanceof Employee, //true
employee2 instanceof Person, //true
employee == employee2); //false在上面的代碼里,我們改變了 Serializable,讓它成為一個(gè)動(dòng)態(tài)返回類型的函數(shù),然后我們通過(guò) class Employ extends Serializable(Person) 來(lái)實(shí)現(xiàn)可序列化,在這里我們沒(méi)有可序列化 Person 本身,而將 Serializable 在語(yǔ)義上變成一種修飾,即 Employee 是一種可序列化的 Person。于是,我們要 new Person 就不會(huì)報(bào)錯(cuò)了:
let person = new Person("john", 22, "m");
//Person {name: "john", age: 22, gender: "m"}這么做了之后,我們還可以實(shí)現(xiàn)對(duì)原生類的繼承,例如:
繼承原生的 Set 類
const Serializable = Sup => class extends Sup {
constructor(...args){
super(...args);
if(typeof this.constructor.stringify !== "function"){
throw new ReferenceError("Please define stringify method to the Class!");
}
if(typeof this.constructor.parse !== "function"){
throw new ReferenceError("Please define parse method to the Class!");
}
}
toString(){
return this.constructor.stringify(this);
}
}
class MySet extends Serializable(Set){
static stringify(s){
return JSON.stringify([...s]);
}
static parse(data){
return new MySet(JSON.parse(data));
}
}
let s1 = new MySet([1,2,3,4]);
let s2 = MySet.parse(s1 + "");
console.log(s2, //Set{1,2,3,4}
s1 == s2); //false通過(guò) MySet 繼承 Serializable(Set),我們得到了一個(gè)可序列化的 Set 類!同樣我們還可以實(shí)現(xiàn)可序列化的 Map:
class MyMap extends Serializable(Map){
...
static stringify(map){
...
}
static parse(str){
...
}
}如果不用 mixin 模式而使用繼承,我們就得分別定義不同的類來(lái)對(duì)應(yīng) Set 和 Map 的繼承,而用了 mixin 模式,我們構(gòu)造出了通用的 Serializable,它可以用來(lái)“修飾”任何對(duì)象。
我們還可以定義其他的“修飾符”,然后將它們組合使用,比如:
const Serializable = Sup => class extends Sup {
constructor(...args){
super(...args);
if(typeof this.constructor.stringify !== "function"){
throw new ReferenceError("Please define stringify method to the Class!");
}
if(typeof this.constructor.parse !== "function"){
throw new ReferenceError("Please define parse method to the Class!");
}
}
toString(){
return this.constructor.stringify(this);
}
}
const Immutable = Sup => class extends Sup {
constructor(...args){
super(...args);
Object.freeze(this);
}
}
class MyArray extends Immutable(Serializable(Array)){
static stringify(arr){
return JSON.stringify({Immutable:arr});
}
static parse(data){
return new MyArray(...JSON.parse(data).Immutable);
}
}
let arr1 = new MyArray(1,2,3,4);
let arr2 = MyArray.parse(arr1 + "");
console.log(arr1, arr2,
arr1+"", //{"Immutable":[1,2,3,4]}
arr1 == arr2);
arr1.push(5); //throw Error!上面的例子里,我們通過(guò) Immutable 修飾符定義了一個(gè)不可變數(shù)組,同時(shí)通過(guò) Serializable 修飾符修改了它的序列化存儲(chǔ)方式,而這一切,通過(guò)定義 class MyArray extends Immutable(Serializable(Array)) 來(lái)實(shí)現(xiàn)。
感謝你能夠認(rèn)真閱讀完這篇文章,希望小編分享react高階組件和ES6裝飾器的使用示例內(nèi)容對(duì)大家有幫助,同時(shí)也希望大家多多支持創(chuàng)新互聯(lián),關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,遇到問(wèn)題就找創(chuàng)新互聯(lián),詳細(xì)的解決方法等著你來(lái)學(xué)習(xí)!
網(wǎng)站名稱:react高階組件和ES6裝飾器的使用示例
URL網(wǎng)址:http://www.chinadenli.net/article36/peespg.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、微信小程序、外貿(mào)建站、建站公司、品牌網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)